| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| example.js | 100% | (83 / 83) | 100% | (73 / 73) | 100% | (12 / 12) | 100% | (83 / 83) | |
| lib.npmtest_parse_server.js | 100% | (16 / 16) | 100% | (14 / 14) | 100% | (3 / 3) | 100% | (16 / 16) | |
| test.js | 100% | (54 / 54) | 100% | (39 / 39) | 100% | (13 / 13) | 100% | (54 / 54) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 1 2 2 3 3 3 3 1 3 3 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 6 6 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /*
example.js
quickstart example
instruction
1. save this script as example.js
2. run the shell command:
$ npm install npmtest-parse-server && PORT=8081 node example.js
3. play with the browser-demo on http://127.0.0.1:8081
*/
/* istanbul instrument in package npmtest_parse_server */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || (local.modeJs === 'browser'
? local.global.utility2_npmtest_parse_server
: global.utility2_moduleExports);
// export local
local.global.local = local;
}());
switch (local.modeJs) {
// post-init
// run browser js-env code - post-init
/* istanbul ignore next */
case 'browser':
local.testRunBrowser = function (event) {
Eif (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('onreset'))) {
// reset output
Array.from(
document.querySelectorAll('body > .resettable')
).forEach(function (element) {
switch (element.tagName) {
case 'INPUT':
case 'TEXTAREA':
element.value = '';
break;
default:
element.textContent = '';
}
});
}
switch (event && event.currentTarget && event.currentTarget.id) {
case 'testRunButton1':
// show tests
Eif (document.querySelector('#testReportDiv1').style.display === 'none') {
document.querySelector('#testReportDiv1').style.display = 'block';
document.querySelector('#testRunButton1').textContent =
'hide internal test';
local.modeTest = true;
local.testRunDefault(local);
// hide tests
} else {
document.querySelector('#testReportDiv1').style.display = 'none';
document.querySelector('#testRunButton1').textContent = 'run internal test';
}
break;
// custom-case
default:
break;
}
Iif (document.querySelector('#inputTextareaEval1') && (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('oneval')))) {
// try to eval input-code
try {
/*jslint evil: true*/
eval(document.querySelector('#inputTextareaEval1').value);
} catch (errorCaught) {
console.error(errorCaught);
}
}
};
// log stderr and stdout to #outputTextareaStdout1
['error', 'log'].forEach(function (key) {
console[key + '_original'] = console[key];
console[key] = function () {
var element;
console[key + '_original'].apply(console, arguments);
element = document.querySelector('#outputTextareaStdout1');
Iif (!element) {
return;
}
// append text to #outputTextareaStdout1
element.value += Array.from(arguments).map(function (arg) {
return typeof arg === 'string'
? arg
: JSON.stringify(arg, null, 4);
}).join(' ') + '\n';
// scroll textarea to bottom
element.scrollTop = element.scrollHeight;
};
});
// init event-handling
['change', 'click', 'keyup'].forEach(function (event) {
Array.from(document.querySelectorAll('.on' + event)).forEach(function (element) {
element.addEventListener(event, local.testRunBrowser);
});
});
// run tests
local.testRunBrowser();
break;
// run node js-env code - post-init
/* istanbul ignore next */
case 'node':
// export local
module.exports = local;
// require modules
local.fs = require('fs');
local.http = require('http');
local.url = require('url');
// init assets
local.assetsDict = local.assetsDict || {};
/* jslint-ignore-begin */
local.assetsDict['/assets.index.template.html'] = '\
<!doctype html>\n\
<html lang="en">\n\
<head>\n\
<meta charset="UTF-8">\n\
<meta name="viewport" content="width=device-width, initial-scale=1">\n\
<title>{{env.npm_package_name}} (v{{env.npm_package_version}})</title>\n\
<style>\n\
/*csslint\n\
box-sizing: false,\n\
universal-selector: false\n\
*/\n\
* {\n\
box-sizing: border-box;\n\
}\n\
body {\n\
background: #dde;\n\
font-family: Arial, Helvetica, sans-serif;\n\
margin: 2rem;\n\
}\n\
body > * {\n\
margin-bottom: 1rem;\n\
}\n\
.utility2FooterDiv {\n\
margin-top: 20px;\n\
text-align: center;\n\
}\n\
</style>\n\
<style>\n\
/*csslint\n\
*/\n\
textarea {\n\
font-family: monospace;\n\
height: 10rem;\n\
width: 100%;\n\
}\n\
textarea[readonly] {\n\
background: #ddd;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<!-- utility2-comment\n\
<div id="ajaxProgressDiv1" style="background: #d00; height: 2px; left: 0; margin: 0; padding: 0; position: fixed; top: 0; transition: background 0.5s, width 1.5s; width: 25%;"></div>\n\
utility2-comment -->\n\
<h1>\n\
<!-- utility2-comment\n\
<a\n\
{{#if env.npm_package_homepage}}\n\
href="{{env.npm_package_homepage}}"\n\
{{/if env.npm_package_homepage}}\n\
target="_blank"\n\
>\n\
utility2-comment -->\n\
{{env.npm_package_name}} (v{{env.npm_package_version}})\n\
<!-- utility2-comment\n\
</a>\n\
utility2-comment -->\n\
</h1>\n\
<h3>{{env.npm_package_description}}</h3>\n\
<!-- utility2-comment\n\
<h4><a download href="assets.app.js">download standalone app</a></h4>\n\
<button class="onclick onreset" id="testRunButton1">run internal test</button><br>\n\
<div id="testReportDiv1" style="display: none;"></div>\n\
utility2-comment -->\n\
\n\
\n\
\n\
<label>stderr and stdout</label>\n\
<textarea class="resettable" id="outputTextareaStdout1" readonly></textarea>\n\
<!-- utility2-comment\n\
{{#if isRollup}}\n\
<script src="assets.app.js"></script>\n\
{{#unless isRollup}}\n\
utility2-comment -->\n\
<script src="assets.utility2.rollup.js"></script>\n\
<script src="jsonp.utility2._stateInit?callback=window.utility2._stateInit"></script>\n\
<script src="assets.npmtest_parse_server.rollup.js"></script>\n\
<script src="assets.example.js"></script>\n\
<script src="assets.test.js"></script>\n\
<!-- utility2-comment\n\
{{/if isRollup}}\n\
utility2-comment -->\n\
<div class="utility2FooterDiv">\n\
[ this app was created with\n\
<a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\
]\n\
</div>\n\
</body>\n\
</html>\n\
';
/* jslint-ignore-end */
Iif (local.templateRender) {
local.assetsDict['/'] = local.templateRender(
local.assetsDict['/assets.index.template.html'],
{
env: local.objectSetDefault(local.env, {
npm_package_description: 'the greatest app in the world!',
npm_package_name: 'my-app',
npm_package_nameAlias: 'my_app',
npm_package_version: '0.0.1'
})
}
);
} else {
local.assetsDict['/'] = local.assetsDict['/assets.index.template.html']
.replace((/\{\{env\.(\w+?)\}\}/g), function (match0, match1) {
// jslint-hack
String(match0);
switch (match1) {
case 'npm_package_description':
return 'the greatest app in the world!';
case 'npm_package_name':
return 'my-app';
case 'npm_package_nameAlias':
return 'my_app';
case 'npm_package_version':
return '0.0.1';
}
});
}
// run the cli
Eif (local.global.utility2_rollup || module !== require.main) {
break;
}
local.assetsDict['/assets.example.js'] =
local.assetsDict['/assets.example.js'] ||
local.fs.readFileSync(__filename, 'utf8');
// bug-workaround - long $npm_package_buildCustomOrg
/* jslint-ignore-begin */
local.assetsDict['/assets.npmtest_parse_server.rollup.js'] =
local.assetsDict['/assets.npmtest_parse_server.rollup.js'] ||
local.fs.readFileSync(
local.npmtest_parse_server.__dirname + '/lib.npmtest_parse_server.js',
'utf8'
).replace((/^#!/), '//');
/* jslint-ignore-end */
local.assetsDict['/favicon.ico'] = local.assetsDict['/favicon.ico'] || '';
// if $npm_config_timeout_exit exists,
// then exit this process after $npm_config_timeout_exit ms
if (Number(process.env.npm_config_timeout_exit)) {
setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
}
// start server
if (local.global.utility2_serverHttp1) {
break;
}
process.env.PORT = process.env.PORT || '8081';
console.error('server starting on port ' + process.env.PORT);
local.http.createServer(function (request, response) {
request.urlParsed = local.url.parse(request.url);
if (local.assetsDict[request.urlParsed.pathname] !== undefined) {
response.end(local.assetsDict[request.urlParsed.pathname]);
return;
}
response.statusCode = 404;
response.end();
}).listen(process.env.PORT);
break;
}
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 2 2 2 2 2 2 2 1 2 2 2 2 1 1 1 1 | /* istanbul instrument in package npmtest_parse_server */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || local;
// init lib
local.local = local.npmtest_parse_server = local;
// init exports
if (local.modeJs === 'browser') {
local.global.utility2_npmtest_parse_server = local;
} else {
module.exports = local;
module.exports.__dirname = __dirname;
module.exports.module = module;
}
}());
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | 2 2 2 2 2 2 2 1 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2 1 2 2 1 2 2 1 1 1 1 1 | /* istanbul instrument in package npmtest_parse_server */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
switch (local.modeJs) {
// re-init local from window.local
case 'browser':
local = local.global.utility2.objectSetDefault(
local.global.utility2_rollup || local.global.local,
local.global.utility2
);
break;
// re-init local from example.js
case 'node':
local = (local.global.utility2_rollup || require('utility2'))
.requireReadme();
break;
}
// export local
local.global.local = local;
}());
// run shared js-env code - function
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - function
case 'browser':
break;
// run node js-env code - function
case 'node':
break;
}
// run shared js-env code - post-init
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - post-init
case 'browser':
local.testCase_browser_nullCase = local.testCase_browser_nullCase || function (
options,
onError
) {
/*
* this function will test browsers's null-case handling-behavior-behavior
*/
onError(null, options);
};
// run tests
local.nop(local.modeTest &&
document.querySelector('#testRunButton1') &&
document.querySelector('#testRunButton1').click());
break;
// run node js-env code - post-init
/* istanbul ignore next */
case 'node':
local.testCase_buildApidoc_default = local.testCase_buildApidoc_default || function (
options,
onError
) {
/*
* this function will test buildApidoc's default handling-behavior-behavior
*/
options = { modulePathList: module.paths };
local.buildApidoc(options, onError);
};
local.testCase_buildApp_default = local.testCase_buildApp_default || function (
options,
onError
) {
/*
* this function will test buildApp's default handling-behavior-behavior
*/
local.testCase_buildReadme_default(options, local.onErrorThrow);
local.testCase_buildLib_default(options, local.onErrorThrow);
local.testCase_buildTest_default(options, local.onErrorThrow);
local.testCase_buildCustomOrg_default(options, local.onErrorThrow);
options = [];
local.buildApp(options, onError);
};
local.testCase_buildCustomOrg_default = local.testCase_buildCustomOrg_default ||
function (options, onError) {
/*
* this function will test buildCustomOrg's default handling-behavior
*/
options = {};
local.buildCustomOrg(options, onError);
};
local.testCase_buildLib_default = local.testCase_buildLib_default || function (
options,
onError
) {
/*
* this function will test buildLib's default handling-behavior
*/
options = {};
local.buildLib(options, onError);
};
local.testCase_buildReadme_default = local.testCase_buildReadme_default || function (
options,
onError
) {
/*
* this function will test buildReadme's default handling-behavior-behavior
*/
options = {};
local.buildReadme(options, onError);
};
local.testCase_buildTest_default = local.testCase_buildTest_default || function (
options,
onError
) {
/*
* this function will test buildTest's default handling-behavior
*/
options = {};
local.buildTest(options, onError);
};
local.testCase_webpage_default = local.testCase_webpage_default || function (
options,
onError
) {
/*
* this function will test webpage's default handling-behavior
*/
options = { modeCoverageMerge: true, url: local.serverLocalHost + '?modeTest=1' };
local.browserTest(options, onError);
};
// run test-server
local.testRunServer(local);
break;
}
}());
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 22.58% | (14 / 62) | 0% | (0 / 24) | 0% | (0 / 11) | 22.58% | (14 / 62) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
// FileSystemAdapter
//
// Stores files in local file system
// Requires write access to the server's file system.
var fs = require('fs');
var path = require('path');
var pathSep = require('path').sep;
function FileSystemAdapter(options) {
options = options || {};
let filesSubDirectory = options.filesSubDirectory || '';
this._filesDir = filesSubDirectory;
this._mkdir(this._getApplicationDir());
if (!this._applicationDirExist()) {
throw "Files directory doesn't exist.";
}
}
FileSystemAdapter.prototype.createFile = function(filename, data) {
return new Promise((resolve, reject) => {
let filepath = this._getLocalFilePath(filename);
fs.writeFile(filepath, data, (err) => {
if(err !== null) {
return reject(err);
}
resolve(data);
});
});
}
FileSystemAdapter.prototype.deleteFile = function(filename) {
return new Promise((resolve, reject) => {
let filepath = this._getLocalFilePath(filename);
fs.readFile( filepath , function (err, data) {
if(err !== null) {
return reject(err);
}
fs.unlink(filepath, (unlinkErr) => {
if(err !== null) {
return reject(unlinkErr);
}
resolve(data);
});
});
});
}
FileSystemAdapter.prototype.getFileData = function(filename) {
return new Promise((resolve, reject) => {
let filepath = this._getLocalFilePath(filename);
fs.readFile( filepath , function (err, data) {
if(err !== null) {
return reject(err);
}
resolve(data);
});
});
}
FileSystemAdapter.prototype.getFileLocation = function(config, filename) {
return config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename);
}
/*
Helpers
--------------- */
FileSystemAdapter.prototype._getApplicationDir = function() {
if (this._filesDir) {
return path.join('files', this._filesDir);
} else {
return 'files';
}
}
FileSystemAdapter.prototype._applicationDirExist = function() {
return fs.existsSync(this._getApplicationDir());
}
FileSystemAdapter.prototype._getLocalFilePath = function(filename) {
let applicationDir = this._getApplicationDir();
if (!fs.existsSync(applicationDir)) {
this._mkdir(applicationDir);
}
return path.join(applicationDir, encodeURIComponent(filename));
}
FileSystemAdapter.prototype._mkdir = function(dirPath) {
// snippet found on -> https://gist.github.com/danherbert-epam/3960169
let dirs = dirPath.split(pathSep);
var root = "";
while (dirs.length > 0) {
var dir = dirs.shift();
if (dir === "") { // If directory starts with a /, the first path will be an empty string.
root = pathSep;
}
if (!fs.existsSync(path.join(root, dir))) {
try {
fs.mkdirSync(path.join(root, dir));
}
catch (e) {
if ( e.code == 'EACCES' ) {
throw new Error("PERMISSION ERROR: In order to use the FileSystemAdapter, write access to the server's file system is required.");
}
}
}
root = path.join(root, dir, pathSep);
}
}
module.exports = FileSystemAdapter;
module.exports.default = FileSystemAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| APNS.js | 13.33% | (20 / 150) | 10.77% | (7 / 65) | 5% | (1 / 20) | 12.93% | (19 / 147) | |
| GCM.js | 23.91% | (22 / 92) | 14% | (7 / 50) | 7.14% | (1 / 14) | 23.6% | (21 / 89) | |
| ParsePushAdapter.js | 42.86% | (36 / 84) | 21.62% | (8 / 37) | 38.46% | (5 / 13) | 31.34% | (21 / 67) | |
| PushAdapterUtils.js | 12.5% | (6 / 48) | 0% | (0 / 21) | 0% | (0 / 2) | 12.5% | (6 / 48) | |
| index.js | 74.19% | (23 / 31) | 56.25% | (9 / 16) | 100% | (2 / 2) | 95.24% | (20 / 21) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 | "use strict";
// TODO: apn does not support the new HTTP/2 protocal. It is fine to use it in V1,
// but probably we will replace it in the future.
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _apn = require('apn');
var _apn2 = _interopRequireDefault(_apn);
var _parse = require('parse');
var _parse2 = _interopRequireDefault(_parse);
var _npmlog = require('npmlog');
var _npmlog2 = _interopRequireDefault(_npmlog);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var LOG_PREFIX = 'parse-server-push-adapter APNS';
/**
* Create a new connection to the APN service.
* @constructor
* @param {Object|Array} args An argument or a list of arguments to config APNS connection
* @param {String} args.cert The filename of the connection certificate to load from disk
* @param {String} args.key The filename of the connection key to load from disk
* @param {String} args.pfx The filename for private key, certificate and CA certs in PFX or PKCS12 format, it will overwrite cert and key
* @param {String} args.passphrase The passphrase for the connection key, if required
* @param {String} args.bundleId The bundleId for cert
* @param {Boolean} args.production Specifies which environment to connect to: Production (if true) or Sandbox
*/
function APNS(args) {
var _this = this;
// typePushConfig can be an array.
var apnsArgsList = [];
if (Array.isArray(args)) {
apnsArgsList = apnsArgsList.concat(args);
} else if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object') {
apnsArgsList.push(args);
} else {
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'APNS Configuration is invalid');
}
this.conns = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var apnsArgs = _step.value;
var conn = new _apn2.default.Connection(apnsArgs);
if (!apnsArgs.bundleId) {
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'BundleId is mssing for %j', apnsArgs);
}
conn.bundleId = apnsArgs.bundleId;
// Set the priority of the conns, prod cert has higher priority
if (apnsArgs.production) {
conn.priority = 0;
} else {
conn.priority = 1;
}
// Set apns client callbacks
conn.on('connected', function () {
_npmlog2.default.verbose(LOG_PREFIX, 'APNS Connection %d Connected', conn.index);
});
conn.on('transmissionError', function (errCode, notification, apnDevice) {
handleTransmissionError(_this.conns, errCode, notification, apnDevice);
});
conn.on('timeout', function () {
_npmlog2.default.verbose(LOG_PREFIX, 'APNS Connection %d Timeout', conn.index);
});
conn.on('disconnected', function () {
_npmlog2.default.verbose(LOG_PREFIX, 'APNS Connection %d Disconnected', conn.index);
});
conn.on('socketError', function () {
_npmlog2.default.verbose(LOG_PREFIX, 'APNS Connection %d Socket Error', conn.index);
});
conn.on('transmitted', function (notification, device) {
if (device.callback) {
device.callback({
notification: notification,
transmitted: true,
device: {
deviceType: device.deviceType,
deviceToken: device.token.toString('hex')
}
});
}
_npmlog2.default.verbose(LOG_PREFIX, 'APNS Connection %d Notification transmitted to %s', conn.index, device.token.toString('hex'));
});
_this.conns.push(conn);
};
for (var _iterator = apnsArgsList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
// Sort the conn based on priority ascending, high pri first
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
this.conns.sort(function (s1, s2) {
return s1.priority - s2.priority;
});
// Set index of conns
for (var index = 0; index < this.conns.length; index++) {
this.conns[index].index = index;
}
}
/**
* Send apns request.
* @param {Object} data The data we need to send, the format is the same with api request body
* @param {Array} devices A array of devices
* @returns {Object} A promise which is resolved immediately
*/
APNS.prototype.send = function (data, devices) {
var _this2 = this;
var coreData = data.data;
var expirationTime = data['expiration_time'];
var notification = generateNotification(coreData, expirationTime);
var allPromises = [];
var devicesPerConnIndex = {};
// Start by clustering the devices per connections
devices.forEach(function (device) {
var qualifiedConnIndexs = chooseConns(_this2.conns, device);
if (qualifiedConnIndexs.length == 0) {
_npmlog2.default.error(LOG_PREFIX, 'no qualified connections for %s %s', device.appIdentifier, device.deviceToken);
var promise = Promise.resolve({
transmitted: false,
device: {
deviceToken: device.deviceToken,
deviceType: device.deviceType
},
result: { error: 'No connection available' }
});
allPromises.push(promise);
} else {
var apnDevice = new _apn2.default.Device(device.deviceToken);
apnDevice.connIndex = qualifiedConnIndexs[0];
if (device.appIdentifier) {
apnDevice.appIdentifier = device.appIdentifier;
}
devicesPerConnIndex[apnDevice.connIndex] = devicesPerConnIndex[apnDevice.connIndex] || [];
devicesPerConnIndex[apnDevice.connIndex].push(apnDevice);
}
});
allPromises = Object.keys(devicesPerConnIndex).reduce(function (memo, connIndex) {
var devices = devicesPerConnIndex[connIndex];
// Create a promise, attach the callback
var promises = devices.map(function (apnDevice) {
return new Promise(function (resolve, reject) {
apnDevice.callback = resolve;
});
});
var conn = _this2.conns[connIndex];
conn.pushNotification(notification, devices);
return memo.concat(promises);
}, allPromises);
return Promise.all(allPromises);
};
function handleTransmissionError(conns, errCode, notification, apnDevice) {
// This means the error notification is not in the cache anymore or the recepient is missing,
// we just ignore this case
if (!notification || !apnDevice) {
return;
}
// If currentConn can not send the push notification, we try to use the next available conn.
// Since conns is sorted by priority, the next conn means the next low pri conn.
// If there is no conn available, we give up on sending the notification to that device.
var qualifiedConnIndexs = chooseConns(conns, apnDevice);
var currentConnIndex = apnDevice.connIndex;
var newConnIndex = -1;
// Find the next element of currentConnIndex in qualifiedConnIndexs
for (var index = 0; index < qualifiedConnIndexs.length - 1; index++) {
if (qualifiedConnIndexs[index] === currentConnIndex) {
newConnIndex = qualifiedConnIndexs[index + 1];
break;
}
}
// There is no more available conns, we give up in this case
if (newConnIndex < 0 || newConnIndex >= conns.length) {
if (apnDevice.callback) {
_npmlog2.default.error(LOG_PREFIX, 'cannot find vaild connection for ' + apnDevice.token.toString('hex'));
apnDevice.callback({
response: { error: 'APNS can not find vaild connection for ' + apnDevice.token.toString('hex'), code: errCode },
status: errCode,
transmitted: false,
device: {
deviceType: apnDevice.deviceType,
deviceToken: apnDevice.token.toString('hex')
}
});
}
return;
}
var newConn = conns[newConnIndex];
// Update device conn info
apnDevice.connIndex = newConnIndex;
// Use the new conn to send the notification
newConn.pushNotification(notification, apnDevice);
}
function chooseConns(conns, device) {
// If device does not have appIdentifier, all conns maybe proper connections.
// Otherwise we try to match the appIdentifier with bundleId
var qualifiedConns = [];
for (var index = 0; index < conns.length; index++) {
var _conn = conns[index];
// If the device we need to send to does not have
// appIdentifier, any conn could be a qualified connection
if (!device.appIdentifier || device.appIdentifier === '') {
qualifiedConns.push(index);
continue;
}
if (device.appIdentifier === _conn.bundleId) {
qualifiedConns.push(index);
}
}
return qualifiedConns;
}
/**
* Generate the apns notification from the data we get from api request.
* @param {Object} coreData The data field under api request body
* @param {number} expirationTime The expiration time in milliseconds since Jan 1 1970
* @returns {Object} A apns notification
*/
function generateNotification(coreData, expirationTime) {
var notification = new _apn2.default.notification();
var payload = {};
for (var key in coreData) {
switch (key) {
case 'alert':
notification.setAlertText(coreData.alert);
break;
case 'badge':
notification.badge = coreData.badge;
break;
case 'sound':
notification.sound = coreData.sound;
break;
case 'content-available':
notification.setNewsstandAvailable(true);
var isAvailable = coreData['content-available'] === 1;
notification.setContentAvailable(isAvailable);
break;
case 'mutable-content':
var isMutable = coreData['mutable-content'] === 1;
notification.setMutableContent(isMutable);
break;
case 'category':
notification.category = coreData.category;
break;
default:
payload[key] = coreData[key];
break;
}
}
notification.payload = payload;
notification.expiry = expirationTime / 1000;
return notification;
}
APNS.generateNotification = generateNotification;
Iif (process.env.TESTING) {
APNS.chooseConns = chooseConns;
APNS.handleTransmissionError = handleTransmissionError;
}
module.exports = APNS;
exports.default = APNS;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _parse = require('parse');
var _parse2 = _interopRequireDefault(_parse);
var _npmlog = require('npmlog');
var _npmlog2 = _interopRequireDefault(_npmlog);
var _nodeGcm = require('node-gcm');
var _nodeGcm2 = _interopRequireDefault(_nodeGcm);
var _PushAdapterUtils = require('./PushAdapterUtils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var LOG_PREFIX = 'parse-server-push-adapter GCM';
var GCMTimeToLiveMax = 4 * 7 * 24 * 60 * 60; // GCM allows a max of 4 weeks
var GCMRegistrationTokensMax = 1000;
function GCM(args) {
if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) !== 'object' || !args.apiKey) {
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'GCM Configuration is invalid');
}
this.sender = new _nodeGcm2.default.Sender(args.apiKey);
}
/**
* Send gcm request.
* @param {Object} data The data we need to send, the format is the same with api request body
* @param {Array} devices A array of devices
* @returns {Object} A promise which is resolved after we get results from gcm
*/
GCM.prototype.send = function (data, devices) {
var _this = this;
var pushId = (0, _PushAdapterUtils.randomString)(10);
// Make a new array
devices = devices.slice(0);
var timestamp = Date.now();
// For android, we can only have 1000 recepients per send, so we need to slice devices to
// chunk if necessary
var slices = sliceDevices(devices, GCMRegistrationTokensMax);
if (slices.length > 1) {
_npmlog2.default.verbose(LOG_PREFIX, 'the number of devices exceeds ' + GCMRegistrationTokensMax);
// Make 1 send per slice
var _promises = slices.reduce(function (memo, slice) {
var promise = _this.send(data, slice, timestamp);
memo.push(promise);
return memo;
}, []);
return _parse2.default.Promise.when(_promises).then(function (results) {
var allResults = results.reduce(function (memo, result) {
return memo.concat(result);
}, []);
return _parse2.default.Promise.as(allResults);
});
}
// get the devices back...
devices = slices[0];
var expirationTime = void 0;
// We handle the expiration_time convertion in push.js, so expiration_time is a valid date
// in Unix epoch time in milliseconds here
if (data['expiration_time']) {
expirationTime = data['expiration_time'];
}
// Generate gcm payload
// PushId is not a formal field of GCM, but Parse Android SDK uses this field to deduplicate push notifications
var gcmPayload = generateGCMPayload(data, pushId, timestamp, expirationTime);
// Make and send gcm request
var message = new _nodeGcm2.default.Message(gcmPayload);
// Build a device map
var devicesMap = devices.reduce(function (memo, device) {
memo[device.deviceToken] = device;
return memo;
}, {});
var deviceTokens = Object.keys(devicesMap);
var promises = deviceTokens.map(function () {
return new _parse2.default.Promise();
});
var registrationTokens = deviceTokens;
var length = registrationTokens.length;
_npmlog2.default.verbose(LOG_PREFIX, 'sending to ' + length + ' ' + (length > 1 ? 'devices' : 'device'));
this.sender.send(message, { registrationTokens: registrationTokens }, 5, function (error, response) {
// example response:
/*
{ "multicast_id":7680139367771848000,
"success":0,
"failure":4,
"canonical_ids":0,
"results":[ {"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"}] }
*/
if (error) {
_npmlog2.default.error(LOG_PREFIX, 'send errored: %s', JSON.stringify(error, null, 4));
} else {
_npmlog2.default.verbose(LOG_PREFIX, 'GCM Response: %s', JSON.stringify(response, null, 4));
}
var _ref = response || {},
results = _ref.results,
multicast_id = _ref.multicast_id;
registrationTokens.forEach(function (token, index) {
var promise = promises[index];
var result = results ? results[index] : undefined;
var device = devicesMap[token];
device.deviceType = 'android';
var resolution = {
device: device,
multicast_id: multicast_id,
response: error || result
};
if (!result || result.error) {
resolution.transmitted = false;
} else {
resolution.transmitted = true;
}
promise.resolve(resolution);
});
});
return _parse2.default.Promise.when(promises);
};
/**
* Generate the gcm payload from the data we get from api request.
* @param {Object} requestData The request body
* @param {String} pushId A random string
* @param {Number} timeStamp A number whose format is the Unix Epoch
* @param {Number|undefined} expirationTime A number whose format is the Unix Epoch or undefined
* @returns {Object} A promise which is resolved after we get results from gcm
*/
function generateGCMPayload(requestData, pushId, timeStamp, expirationTime) {
var payload = {
priority: 'high'
};
payload.data = {
data: requestData.data,
push_id: pushId,
time: new Date(timeStamp).toISOString()
};
if (requestData.content_available) {
payload.content_available = requestData.content_available;
}
if (requestData.notification) {
payload.notification = requestData.notification;
}
if (expirationTime) {
// The timeStamp and expiration is in milliseconds but gcm requires second
var timeToLive = Math.floor((expirationTime - timeStamp) / 1000);
if (timeToLive < 0) {
timeToLive = 0;
}
if (timeToLive >= GCMTimeToLiveMax) {
timeToLive = GCMTimeToLiveMax;
}
payload.timeToLive = timeToLive;
}
return payload;
}
/**
* Slice a list of devices to several list of devices with fixed chunk size.
* @param {Array} devices An array of devices
* @param {Number} chunkSize The size of the a chunk
* @returns {Array} An array which contaisn several arries of devices with fixed chunk size
*/
function sliceDevices(devices, chunkSize) {
var chunkDevices = [];
while (devices.length > 0) {
chunkDevices.push(devices.splice(0, chunkSize));
}
return chunkDevices;
}
GCM.generateGCMPayload = generateGCMPayload;
Iif (process.env.TESTING) {
GCM.sliceDevices = sliceDevices;
}
module.exports = GCM;
exports.default = GCM;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 1 1 3 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParsePushAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _parse = require('parse');
var _parse2 = _interopRequireDefault(_parse);
var _npmlog = require('npmlog');
var _npmlog2 = _interopRequireDefault(_npmlog);
var _APNS = require('./APNS');
var _APNS2 = _interopRequireDefault(_APNS);
var _GCM = require('./GCM');
var _GCM2 = _interopRequireDefault(_GCM);
var _PushAdapterUtils = require('./PushAdapterUtils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var LOG_PREFIX = 'parse-server-push-adapter';
var ParsePushAdapter = exports.ParsePushAdapter = function () {
function ParsePushAdapter() {
var pushConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, ParsePushAdapter);
this.supportsPushTracking = true;
this.validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm'];
this.senderMap = {};
// used in PushController for Dashboard Features
this.feature = {
immediatePush: true
};
var pushTypes = Object.keys(pushConfig);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = pushTypes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var pushType = _step.value;
if (this.validPushTypes.indexOf(pushType) < 0) {
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'Push to ' + pushTypes + ' is not supported');
}
switch (pushType) {
case 'ios':
case 'tvos':
case 'osx':
this.senderMap[pushType] = new _APNS2.default(pushConfig[pushType]);
break;
case 'android':
case 'fcm':
this.senderMap[pushType] = new _GCM2.default(pushConfig[pushType]);
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
_createClass(ParsePushAdapter, [{
key: 'getValidPushTypes',
value: function getValidPushTypes() {
return this.validPushTypes;
}
}, {
key: 'send',
value: function send(data, installations) {
var _this = this;
var deviceMap = (0, _PushAdapterUtils.classifyInstallations)(installations, this.validPushTypes);
var sendPromises = [];
var _loop = function _loop(pushType) {
var sender = _this.senderMap[pushType];
var devices = deviceMap[pushType];
if (Array.isArray(devices) && devices.length > 0) {
if (!sender) {
_npmlog2.default.verbose(LOG_PREFIX, 'Can not find sender for push type ' + pushType + ', ' + data);
var results = devices.map(function (device) {
return Promise.resolve({
device: device,
transmitted: false,
response: { 'error': 'Can not find sender for push type ' + pushType + ', ' + data }
});
});
sendPromises.push(Promise.all(results));
} else {
sendPromises.push(sender.send(data, devices));
}
}
};
for (var pushType in deviceMap) {
_loop(pushType);
}
return Promise.all(sendPromises).then(function (promises) {
// flatten all
return [].concat.apply([], promises);
});
}
}], [{
key: 'classifyInstallations',
value: function classifyInstallations(installations, validTypes) {
return (0, _PushAdapterUtils.classifyInstallations)(installations, validTypes);
}
}]);
return ParsePushAdapter;
}();
exports.default = ParsePushAdapter;
module.exports = ParsePushAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.classifyInstallations = classifyInstallations;
exports.randomString = randomString;
var _crypto = require('crypto');
/**g
* Classify the device token of installations based on its device type.
* @param {Object} installations An array of installations
* @param {Array} validPushTypes An array of valid push types(string)
* @returns {Object} A map whose key is device type and value is an array of device
*/
function classifyInstallations(installations, validPushTypes) {
// Init deviceTokenMap, create a empty array for each valid pushType
var deviceMap = {};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = validPushTypes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var validPushType = _step.value;
deviceMap[validPushType] = [];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = installations[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var installation = _step2.value;
// No deviceToken, ignore
if (!installation.deviceToken) {
continue;
}
var devices = deviceMap[installation.pushType] || deviceMap[installation.deviceType] || null;
if (Array.isArray(devices)) {
devices.push({
deviceToken: installation.deviceToken,
deviceType: installation.deviceType,
appIdentifier: installation.appIdentifier
});
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return deviceMap;
}
function randomString(size) {
if (size === 0) {
throw new Error('Zero-length randomString is useless.');
}
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789';
var objectId = '';
var bytes = (0, _crypto.randomBytes)(size);
for (var i = 0; i < bytes.length; ++i) {
objectId += chars[bytes.readUInt8(i) % chars.length];
}
return objectId;
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 | "use strict";
// ParsePushAdapter is the default implementation of
// PushAdapter, it uses GCM for android push and APNS
// for ios push.
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.utils = exports.GCM = exports.APNS = exports.ParsePushAdapter = undefined;
var _npmlog = require('npmlog');
var _npmlog2 = _interopRequireDefault(_npmlog);
var _ParsePushAdapter = require('./ParsePushAdapter');
var _ParsePushAdapter2 = _interopRequireDefault(_ParsePushAdapter);
var _GCM = require('./GCM');
var _GCM2 = _interopRequireDefault(_GCM);
var _APNS = require('./APNS');
var _APNS2 = _interopRequireDefault(_APNS);
var _PushAdapterUtils = require('./PushAdapterUtils');
var utils = _interopRequireWildcard(_PushAdapterUtils);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Iif (process.env.VERBOSE || process.env.VERBOSE_PARSE_SERVER_PUSH_ADAPTER) {
_npmlog2.default.level = 'verbose';
}exports.default = _ParsePushAdapter2.default;
exports.ParsePushAdapter = _ParsePushAdapter2.default;
exports.APNS = _APNS2.default;
exports.GCM = _GCM2.default;
exports.utils = utils;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| progress-bar.js | 26.35% | (39 / 148) | 11.58% | (11 / 95) | 5.26% | (1 / 19) | 30.71% | (39 / 127) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
var hasUnicode = require("has-unicode")
var ansi = require("ansi")
var align = {
center: require("lodash.pad"),
left: require("lodash.padend"),
right: require("lodash.padstart")
}
var defaultStream = process.stderr
function isTTY() {
return process.stderr.isTTY
}
function getWritableTTYColumns() {
// Writing to the final column wraps the line
// We have to use stdout here, because Node's magic SIGWINCH handler only
// updates process.stdout, not process.stderr
return process.stdout.columns - 1
}
var ProgressBar = module.exports = function (options, cursor) {
Iif (! options) options = {}
Eif (! cursor && options.write) {
cursor = options
options = {}
}
Iif (! cursor) {
cursor = ansi(defaultStream)
}
this.cursor = cursor
this.showing = false
this.theme = options.theme || (hasUnicode() ? ProgressBar.unicode : ProgressBar.ascii)
this.template = options.template || [
{type: "name", separated: true, length: 25},
{type: "spinner", separated: true},
{type: "startgroup"},
{type: "completionbar"},
{type: "endgroup"}
]
this.updatefreq = options.maxUpdateFrequency == null ? 50 : options.maxUpdateFrequency
this.lastName = ""
this.lastCompleted = 0
this.spun = 0
this.last = new Date(0)
var self = this
this._handleSizeChange = function () {
if (!self.showing) return
self.hide()
self.show()
}
}
ProgressBar.prototype = {}
ProgressBar.unicode = {
startgroup: "╢",
endgroup: "╟",
complete: "█",
incomplete: "░",
spinner: "▀▐▄▌",
subsection: "→"
}
ProgressBar.ascii = {
startgroup: "|",
endgroup: "|",
complete: "#",
incomplete: "-",
spinner: "-\\|/",
subsection: "->"
}
ProgressBar.prototype.setTheme = function(theme) {
this.theme = theme
}
ProgressBar.prototype.setTemplate = function(template) {
this.template = template
}
ProgressBar.prototype._enableResizeEvents = function() {
process.stdout.on('resize', this._handleSizeChange)
}
ProgressBar.prototype._disableResizeEvents = function() {
process.stdout.removeListener('resize', this._handleSizeChange)
}
ProgressBar.prototype.disable = function() {
this.hide()
this.disabled = true
}
ProgressBar.prototype.enable = function() {
this.disabled = false
this.show()
}
ProgressBar.prototype.hide = function() {
if (!isTTY()) return
if (this.disabled) return
this.cursor.show()
if (this.showing) this.cursor.up(1)
this.cursor.horizontalAbsolute(0).eraseLine()
this.showing = false
}
var repeat = function (str, count) {
var out = ""
for (var ii=0; ii<count; ++ii) out += str
return out
}
ProgressBar.prototype.pulse = function(name) {
++ this.spun
if (! this.showing) return
if (this.disabled) return
var baseName = this.lastName
name = name
? ( baseName
? baseName + " " + this.theme.subsection + " " + name
: null )
: baseName
this.show(name)
this.lastName = baseName
}
ProgressBar.prototype.show = function(name, completed) {
name = this.lastName = name || this.lastName
completed = this.lastCompleted = completed || this.lastCompleted
if (!isTTY()) return
if (this.disabled) return
if (! this.spun && ! completed) return
if (this.tryAgain) return
var self = this
if (this.showing && new Date() - this.last < this.updatefreq) {
this.tryAgain = setTimeout(function () {
self.tryAgain = null
if (self.disabled) return
if (! self.spun && ! completed) return
drawBar()
}, this.updatefreq - (new Date() - this.last))
return
}
return drawBar()
function drawBar() {
var values = {
name: name,
spinner: self.spun,
completed: completed
}
self.last = new Date()
var statusline = self.renderTemplate(self.theme, self.template, values)
if (self.showing) self.cursor.up(1)
self.cursor
.hide()
.horizontalAbsolute(0)
.write(statusline.substr(0, getWritableTTYColumns()) + "\n")
.show()
self.showing = true
}
}
ProgressBar.prototype.renderTemplate = function (theme, template, values) {
values.startgroup = theme.startgroup
values.endgroup = theme.endgroup
values.spinner = values.spinner
? theme.spinner.substr(values.spinner % theme.spinner.length,1)
: ""
var output = {prebar: "", postbar: ""}
var status = "prebar"
var self = this
template.forEach(function(T) {
if (typeof T === "string") {
output[status] += T
return
}
if (T.type === "completionbar") {
status = "postbar"
return
}
if (!values.hasOwnProperty(T.type)) throw new Error("Unknown template value '"+T.type+"'")
var value = self.renderValue(T, values[T.type])
if (value === "") return
var sofar = output[status].length
var lastChar = sofar ? output[status][sofar-1] : null
if (T.separated && sofar && lastChar !== " ") {
output[status] += " "
}
output[status] += value
if (T.separated) output[status] += " "
})
var bar = ""
if (status === "postbar") {
var nonBarLen = output.prebar.length + output.postbar.length
var barLen = getWritableTTYColumns() - nonBarLen
var sofar = Math.round(barLen * Math.max(0,Math.min(1,values.completed||0)))
var rest = barLen - sofar
bar = repeat(theme.complete, sofar)
+ repeat(theme.incomplete, rest)
}
return output.prebar + bar + output.postbar
}
ProgressBar.prototype.renderValue = function (template, value) {
if (value == null || value === "") return ""
var maxLength = template.maxLength || template.length
var minLength = template.minLength || template.length
var alignWith = align[template.align] || align.left
// if (maxLength) value = value.substr(-1 * maxLength)
if (maxLength) value = value.substr(0, maxLength)
if (minLength) value = alignWith(value, minLength)
return value
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| log.js | 29.15% | (58 / 199) | 3.41% | (3 / 88) | 7.41% | (2 / 27) | 33.73% | (56 / 166) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 7 7 7 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'
var Progress = require('are-we-there-yet')
var Gauge = require('gauge')
var EE = require('events').EventEmitter
var log = exports = module.exports = new EE
var util = require('util')
var ansi = require('ansi')
log.cursor = ansi(process.stderr)
log.stream = process.stderr
// by default, let ansi decide based on tty-ness.
var colorEnabled = undefined
log.enableColor = function () {
colorEnabled = true
this.cursor.enabled = true
}
log.disableColor = function () {
colorEnabled = false
this.cursor.enabled = false
}
// default level
log.level = 'info'
log.gauge = new Gauge(log.cursor)
log.tracker = new Progress.TrackerGroup()
// no progress bars unless asked
log.progressEnabled = false
var gaugeTheme = undefined
log.enableUnicode = function () {
gaugeTheme = Gauge.unicode
log.gauge.setTheme(gaugeTheme)
}
log.disableUnicode = function () {
gaugeTheme = Gauge.ascii
log.gauge.setTheme(gaugeTheme)
}
var gaugeTemplate = undefined
log.setGaugeTemplate = function (template) {
gaugeTemplate = template
log.gauge.setTemplate(gaugeTemplate)
}
log.enableProgress = function () {
if (this.progressEnabled) return
this.progressEnabled = true
if (this._pause) return
this.tracker.on('change', this.showProgress)
this.gauge.enable()
this.showProgress()
}
log.disableProgress = function () {
if (!this.progressEnabled) return
this.clearProgress()
this.progressEnabled = false
this.tracker.removeListener('change', this.showProgress)
this.gauge.disable()
}
var trackerConstructors = ['newGroup', 'newItem', 'newStream']
var mixinLog = function (tracker) {
// mixin the public methods from log into the tracker
// (except: conflicts and one's we handle specially)
Object.keys(log).forEach(function (P) {
if (P[0] === '_') return
if (trackerConstructors.filter(function (C) { return C === P }).length) return
if (tracker[P]) return
if (typeof log[P] !== 'function') return
var func = log[P]
tracker[P] = function () {
return func.apply(log, arguments)
}
})
// if the new tracker is a group, make sure any subtrackers get
// mixed in too
if (tracker instanceof Progress.TrackerGroup) {
trackerConstructors.forEach(function (C) {
var func = tracker[C]
tracker[C] = function () { return mixinLog(func.apply(tracker, arguments)) }
})
}
return tracker
}
// Add tracker constructors to the top level log object
trackerConstructors.forEach(function (C) {
log[C] = function () { return mixinLog(this.tracker[C].apply(this.tracker, arguments)) }
})
log.clearProgress = function () {
if (!this.progressEnabled) return
this.gauge.hide()
}
log.showProgress = function (name, completed) {
if (!this.progressEnabled) return
if (completed == null) completed = this.tracker.completed()
this.gauge.show(name, completed)
}.bind(log) // bind for use in tracker's on-change listener
// temporarily stop emitting, but don't drop
log.pause = function () {
this._paused = true
}
log.resume = function () {
if (!this._paused) return
this._paused = false
var b = this._buffer
this._buffer = []
b.forEach(function (m) {
this.emitLog(m)
}, this)
if (this.progressEnabled) this.enableProgress()
}
log._buffer = []
var id = 0
log.record = []
log.maxRecordSize = 10000
log.log = function (lvl, prefix, message) {
var l = this.levels[lvl]
if (l === undefined) {
return this.emit('error', new Error(util.format(
'Undefined log level: %j', lvl)))
}
var a = new Array(arguments.length - 2)
var stack = null
for (var i = 2; i < arguments.length; i ++) {
var arg = a[i-2] = arguments[i]
// resolve stack traces to a plain string.
if (typeof arg === 'object' && arg &&
(arg instanceof Error) && arg.stack) {
arg.stack = stack = arg.stack + ''
}
}
if (stack) a.unshift(stack + '\n')
message = util.format.apply(util, a)
var m = { id: id++,
level: lvl,
prefix: String(prefix || ''),
message: message,
messageRaw: a }
this.emit('log', m)
this.emit('log.' + lvl, m)
if (m.prefix) this.emit(m.prefix, m)
this.record.push(m)
var mrs = this.maxRecordSize
var n = this.record.length - mrs
if (n > mrs / 10) {
var newSize = Math.floor(mrs * 0.9)
this.record = this.record.slice(-1 * newSize)
}
this.emitLog(m)
}.bind(log)
log.emitLog = function (m) {
if (this._paused) {
this._buffer.push(m)
return
}
if (this.progressEnabled) this.gauge.pulse(m.prefix)
var l = this.levels[m.level]
if (l === undefined) return
if (l < this.levels[this.level]) return
if (l > 0 && !isFinite(l)) return
var style = log.style[m.level]
var disp = log.disp[m.level] || m.level
this.clearProgress()
m.message.split(/\r?\n/).forEach(function (line) {
if (this.heading) {
this.write(this.heading, this.headingStyle)
this.write(' ')
}
this.write(disp, log.style[m.level])
var p = m.prefix || ''
if (p) this.write(' ')
this.write(p, this.prefixStyle)
this.write(' ' + line + '\n')
}, this)
this.showProgress()
}
log.write = function (msg, style) {
if (!this.cursor) return
if (this.stream !== this.cursor.stream) {
this.cursor = ansi(this.stream, { enabled: colorEnabled })
var options = {}
if (gaugeTheme != null) options.theme = gaugeTheme
if (gaugeTemplate != null) options.template = gaugeTemplate
this.gauge = new Gauge(options, this.cursor)
}
style = style || {}
if (style.fg) this.cursor.fg[style.fg]()
if (style.bg) this.cursor.bg[style.bg]()
if (style.bold) this.cursor.bold()
if (style.underline) this.cursor.underline()
if (style.inverse) this.cursor.inverse()
if (style.beep) this.cursor.beep()
this.cursor.write(msg).reset()
}
log.addLevel = function (lvl, n, style, disp) {
if (!disp) disp = lvl
this.levels[lvl] = n
this.style[lvl] = style
Eif (!this[lvl]) this[lvl] = function () {
var a = new Array(arguments.length + 1)
a[0] = lvl
for (var i = 0; i < arguments.length; i ++) {
a[i + 1] = arguments[i]
}
return this.log.apply(this, a)
}.bind(this)
this.disp[lvl] = disp
}
log.prefixStyle = { fg: 'magenta' }
log.headingStyle = { fg: 'white', bg: 'black' }
log.style = {}
log.levels = {}
log.disp = {}
log.addLevel('silly', -Infinity, { inverse: true }, 'sill')
log.addLevel('verbose', 1000, { fg: 'blue', bg: 'black' }, 'verb')
log.addLevel('info', 2000, { fg: 'green' })
log.addLevel('http', 3000, { fg: 'green', bg: 'black' })
log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN')
log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!')
log.addLevel('silent', Infinity)
// allow 'error' prefix
log.on('error', function(){})
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 14.08% | (10 / 71) | 0% | (0 / 30) | 0% | (0 / 6) | 14.08% | (10 / 71) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 1 1 1 1 1 1 1 1 1 1 | 'use strict';
// S3Adapter
//
// Stores Parse files in AWS S3.
var AWS = require('aws-sdk');
var optionsFromArguments = require('./lib/optionsFromArguments');
// Creates an S3 session.
// Providing AWS access, secret keys and bucket are mandatory
// Region will use sane defaults if omitted
function S3Adapter() {
var options = optionsFromArguments(arguments);
this._region = options.region;
this._bucket = options.bucket;
this._bucketPrefix = options.bucketPrefix;
this._directAccess = options.directAccess;
this._baseUrl = options.baseUrl;
this._baseUrlDirect = options.baseUrlDirect;
this._signatureVersion = options.signatureVersion;
this._globalCacheControl = options.globalCacheControl;
let s3Options = {
params: { Bucket: this._bucket },
region: this._region,
signatureVersion: this._signatureVersion,
globalCacheControl: this._globalCacheControl
};
if (options.accessKey && options.secretKey) {
s3Options.accessKeyId = options.accessKey;
s3Options.secretAccessKey = options.secretKey;
}
Object.assign(s3Options, options.s3overrides);
this._s3Client = new AWS.S3(s3Options);
this._hasBucket = false;
}
S3Adapter.prototype.createBucket = function() {
var promise;
if (this._hasBucket) {
promise = Promise.resolve();
} else {
promise = new Promise((resolve) => {
this._s3Client.createBucket(() => {
this._hasBucket = true;
resolve();
});
});
}
return promise;
}
// For a given config object, filename, and data, store a file in S3
// Returns a promise containing the S3 object creation response
S3Adapter.prototype.createFile = function(filename, data, contentType) {
let params = {
Key: this._bucketPrefix + filename,
Body: data
};
if (this._directAccess) {
params.ACL = "public-read"
}
if (contentType) {
params.ContentType = contentType;
}
if(this._globalCacheControl) {
params.CacheControl = this._globalCacheControl;
}
return this.createBucket().then(() => {
return new Promise((resolve, reject) => {
this._s3Client.upload(params, (err, data) => {
if (err !== null) {
return reject(err);
}
resolve(data);
});
});
});
}
S3Adapter.prototype.deleteFile = function(filename) {
return this.createBucket().then(() => {
return new Promise((resolve, reject) => {
let params = {
Key: this._bucketPrefix + filename
};
this._s3Client.deleteObject(params, (err, data) =>{
if(err !== null) {
return reject(err);
}
resolve(data);
});
});
});
}
// Search for and return a file if found by filename
// Returns a promise that succeeds with the buffer result from S3
S3Adapter.prototype.getFileData = function(filename) {
let params = {Key: this._bucketPrefix + filename};
return this.createBucket().then(() => {
return new Promise((resolve, reject) => {
this._s3Client.getObject(params, (err, data) => {
if (err !== null) {
return reject(err);
}
// Something happened here...
if (data && !data.Body) {
return reject(data);
}
resolve(data.Body);
});
});
});
}
// Generates and returns the location of a file stored in S3 for the given request and filename
// The location is the direct S3 link if the option is set, otherwise we serve the file through parse-server
S3Adapter.prototype.getFileLocation = function(config, filename) {
filename = encodeURIComponent(filename);
if (this._directAccess) {
if (this._baseUrl && this._baseUrlDirect) {
return `${this._baseUrl}/${filename}`;
} else if (this._baseUrl) {
return `${this._baseUrl}/${this._bucketPrefix + filename}`;
} else {
return `https://${this._bucket}.s3.amazonaws.com/${this._bucketPrefix + filename}`;
}
}
return (config.mount + '/files/' + config.applicationId + '/' + filename);
}
module.exports = S3Adapter;
module.exports.default = S3Adapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| optionsFromArguments.js | 8.77% | (5 / 57) | 0% | (0 / 29) | 0% | (0 / 3) | 8.77% | (5 / 57) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 | 'use strict'; const DEFAULT_S3_REGION = 'us-east-1'; function requiredOrFromEnvironment(options, key, env) { options[key] = options[key] || process.env[env]; if (!options[key]) { throw `S3Adapter requires option '${key}' or env. variable ${env}`; } return options; } function fromEnvironmentOrDefault(options, key, env, defaultValue) { options[key] = options[key] || process.env[env] || defaultValue; return options; } const optionsFromArguments = function optionsFromArguments(args) { const stringOrOptions = args[0]; let options = {}; let s3overrides = {}; let otherOptions; if (typeof stringOrOptions == 'string') { if (args.length == 1) { options.bucket = stringOrOptions; } else if (args.length == 2) { options.bucket = stringOrOptions; if (typeof args[1] != 'object') { throw new Error('Failed to configure S3Adapter. Arguments don\'t make sense'); } otherOptions = args[1]; } else if (args.length > 2) { if (typeof args[1] != 'string' || typeof args[2] != 'string') { throw new Error('Failed to configure S3Adapter. Arguments don\'t make sense'); } options.accessKey = args[0]; options.secretKey = args[1]; options.bucket = args[2]; otherOptions = args[3]; } if (otherOptions) { options.bucketPrefix = otherOptions.bucketPrefix; options.directAccess = otherOptions.directAccess; options.baseUrl = otherOptions.baseUrl; options.baseUrlDirect = otherOptions.baseUrlDirect; options.signatureVersion = otherOptions.signatureVersion; options.globalCacheControl = otherOptions.globalCacheControl; } } else { if (args.length == 1) { Object.assign(options, stringOrOptions); } else if (args.length == 2) { Object.assign(options, stringOrOptions); s3overrides = args[1]; options.bucket = s3overrides.params.Bucket; } else if (args.length > 2) { throw new Error('Failed to configure S3Adapter. Arguments don\'t make sense'); } } options = requiredOrFromEnvironment(options, 'bucket', 'S3_BUCKET'); options = fromEnvironmentOrDefault(options, 'accessKey', 'S3_ACCESS_KEY', null); options = fromEnvironmentOrDefault(options, 'secretKey', 'S3_SECRET_KEY', null); options = fromEnvironmentOrDefault(options, 'bucketPrefix', 'S3_BUCKET_PREFIX', ''); options = fromEnvironmentOrDefault(options, 'region', 'S3_REGION', DEFAULT_S3_REGION); options = fromEnvironmentOrDefault(options, 'directAccess', 'S3_DIRECT_ACCESS', false); options = fromEnvironmentOrDefault(options, 'baseUrl', 'S3_BASE_URL', null); options = fromEnvironmentOrDefault(options, 'baseUrlDirect', 'S3_BASE_URL_DIRECT', false); options = fromEnvironmentOrDefault(options, 'signatureVersion', 'S3_SIGNATURE_VERSION', 'v4'); options = fromEnvironmentOrDefault( options, 'globalCacheControl', 'S3_GLOBAL_CACHE_CONTROL', null); options.s3overrides = s3overrides; return options; } module.exports = optionsFromArguments; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AccountLockout.js | 29.21% | (26 / 89) | 22.86% | (8 / 35) | 13.51% | (5 / 37) | 16.67% | (12 / 72) | |
| Auth.js | 10.32% | (13 / 126) | 0% | (0 / 60) | 0% | (0 / 23) | 10.74% | (13 / 121) | |
| ClientSDK.js | 26.32% | (5 / 19) | 0% | (0 / 8) | 0% | (0 / 4) | 26.32% | (5 / 19) | |
| Config.js | 20.12% | (33 / 164) | 8.33% | (10 / 120) | 18.52% | (5 / 27) | 12.24% | (18 / 147) | |
| ParseMessageQueue.js | 50% | (8 / 16) | 0% | (0 / 4) | 0% | (0 / 2) | 50% | (8 / 16) | |
| ParseServer.js | 46.94% | (92 / 196) | 11.38% | (14 / 123) | 47.37% | (9 / 19) | 44.12% | (75 / 170) | |
| ParseServerRESTController.js | 22.64% | (12 / 53) | 0% | (0 / 35) | 0% | (0 / 13) | 22.64% | (12 / 53) | |
| PromiseRouter.js | 23.03% | (35 / 152) | 13.79% | (12 / 87) | 16.67% | (5 / 30) | 15.91% | (21 / 132) | |
| RestQuery.js | 6.13% | (30 / 489) | 1.1% | (3 / 272) | 0% | (0 / 67) | 6.16% | (30 / 487) | |
| RestWrite.js | 9.09% | (47 / 517) | 0.71% | (3 / 421) | 1.06% | (1 / 94) | 8.98% | (46 / 512) | |
| StatusHandler.js | 13.45% | (16 / 119) | 4.35% | (3 / 69) | 0% | (0 / 26) | 13.68% | (16 / 117) | |
| TestUtils.js | 50% | (7 / 14) | 37.5% | (3 / 8) | 33.33% | (1 / 3) | 46.15% | (6 / 13) | |
| batch.js | 20.93% | (9 / 43) | 0% | (0 / 17) | 0% | (0 / 11) | 20.93% | (9 / 43) | |
| cache.js | 100% | (5 / 5) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (5 / 5) | |
| cryptoUtils.js | 42.86% | (12 / 28) | 0% | (0 / 6) | 0% | (0 / 5) | 42.86% | (12 / 28) | |
| defaults.js | 92.31% | (12 / 13) | 66.67% | (8 / 12) | 100% | (2 / 2) | 92.31% | (12 / 13) | |
| deprecated.js | 80% | (4 / 5) | 100% | (0 / 0) | 50% | (1 / 2) | 80% | (4 / 5) | |
| index.js | 82.98% | (39 / 47) | 58.33% | (7 / 12) | 100% | (3 / 3) | 97.3% | (36 / 37) | |
| logger.js | 94.74% | (18 / 19) | 75% | (3 / 4) | 75% | (3 / 4) | 94.44% | (17 / 18) | |
| middlewares.js | 17.54% | (30 / 171) | 4.12% | (4 / 97) | 6.67% | (1 / 15) | 17.16% | (29 / 169) | |
| password.js | 33.33% | (6 / 18) | 0% | (0 / 8) | 0% | (0 / 6) | 33.33% | (6 / 18) | |
| requiredParameter.js | 100% | (3 / 3) | 100% | (0 / 0) | 100% | (1 / 1) | 100% | (3 / 3) | |
| rest.js | 21.52% | (17 / 79) | 6.12% | (3 / 49) | 5.56% | (1 / 18) | 20.51% | (16 / 78) | |
| triggers.js | 23.55% | (57 / 242) | 3.82% | (6 / 157) | 2.17% | (1 / 46) | 23.53% | (56 / 238) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | 1 1 8 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AccountLockout = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); // This class handles the Account Lockout Policy settings.
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var AccountLockout = exports.AccountLockout = function () {
function AccountLockout(user, config) {
_classCallCheck(this, AccountLockout);
this._user = user;
this._config = config;
}
/**
* set _failed_login_count to value
*/
_createClass(AccountLockout, [{
key: '_setFailedLoginCount',
value: function _setFailedLoginCount(value) {
var query = {
username: this._user.username
};
var updateFields = {
_failed_login_count: value
};
return this._config.database.update('_User', query, updateFields);
}
/**
* check if the _failed_login_count field has been set
*/
}, {
key: '_isFailedLoginCountSet',
value: function _isFailedLoginCountSet() {
var _this = this;
return new Promise(function (resolve, reject) {
var query = {
username: _this._user.username,
_failed_login_count: { $exists: true }
};
_this._config.database.find('_User', query).then(function (users) {
if (Array.isArray(users) && users.length > 0) {
resolve(true);
} else {
resolve(false);
}
}).catch(function (err) {
reject(err);
});
});
}
/**
* if _failed_login_count is NOT set then set it to 0
* else do nothing
*/
}, {
key: '_initFailedLoginCount',
value: function _initFailedLoginCount() {
var _this2 = this;
return new Promise(function (resolve, reject) {
_this2._isFailedLoginCountSet().then(function (failedLoginCountIsSet) {
if (!failedLoginCountIsSet) {
return _this2._setFailedLoginCount(0);
} else {
return Promise.resolve();
}
}).then(function () {
resolve();
}).catch(function (err) {
reject(err);
});
});
}
/**
* increment _failed_login_count by 1
*/
}, {
key: '_incrementFailedLoginCount',
value: function _incrementFailedLoginCount() {
var query = {
username: this._user.username
};
var updateFields = { _failed_login_count: { __op: 'Increment', amount: 1 } };
return this._config.database.update('_User', query, updateFields);
}
/**
* if the failed login count is greater than the threshold
* then sets lockout expiration to 'currenttime + accountPolicy.duration', i.e., account is locked out for the next 'accountPolicy.duration' minutes
* else do nothing
*/
}, {
key: '_setLockoutExpiration',
value: function _setLockoutExpiration() {
var _this3 = this;
return new Promise(function (resolve, reject) {
var query = {
username: _this3._user.username,
_failed_login_count: { $gte: _this3._config.accountLockout.threshold }
};
var now = new Date();
var updateFields = {
_account_lockout_expires_at: _node2.default._encode(new Date(now.getTime() + _this3._config.accountLockout.duration * 60 * 1000))
};
_this3._config.database.update('_User', query, updateFields).then(function () {
resolve();
}).catch(function (err) {
if (err && err.code && err.message && err.code === 101 && err.message === 'Object not found.') {
resolve(); // nothing to update so we are good
} else {
reject(err); // unknown error
}
});
});
}
/**
* if _account_lockout_expires_at > current_time and _failed_login_count > threshold
* reject with account locked error
* else
* resolve
*/
}, {
key: '_notLocked',
value: function _notLocked() {
var _this4 = this;
return new Promise(function (resolve, reject) {
var query = {
username: _this4._user.username,
_account_lockout_expires_at: { $gt: _node2.default._encode(new Date()) },
_failed_login_count: { $gte: _this4._config.accountLockout.threshold }
};
_this4._config.database.find('_User', query).then(function (users) {
if (Array.isArray(users) && users.length > 0) {
reject(new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Your account is locked due to multiple failed login attempts. Please try again after ' + _this4._config.accountLockout.duration + ' minute(s)'));
} else {
resolve();
}
}).catch(function (err) {
reject(err);
});
});
}
/**
* set and/or increment _failed_login_count
* if _failed_login_count > threshold
* set the _account_lockout_expires_at to current_time + accountPolicy.duration
* else
* do nothing
*/
}, {
key: '_handleFailedLoginAttempt',
value: function _handleFailedLoginAttempt() {
var _this5 = this;
return new Promise(function (resolve, reject) {
_this5._initFailedLoginCount().then(function () {
return _this5._incrementFailedLoginCount();
}).then(function () {
return _this5._setLockoutExpiration();
}).then(function () {
resolve();
}).catch(function (err) {
reject(err);
});
});
}
/**
* handle login attempt if the Account Lockout Policy is enabled
*/
}, {
key: 'handleLoginAttempt',
value: function handleLoginAttempt(loginSuccessful) {
var _this6 = this;
if (!this._config.accountLockout) {
return Promise.resolve();
}
return new Promise(function (resolve, reject) {
_this6._notLocked().then(function () {
if (loginSuccessful) {
return _this6._setFailedLoginCount(0);
} else {
return _this6._handleFailedLoginAttempt();
}
}).then(function () {
resolve();
}).catch(function (err) {
reject(err);
});
});
}
}]);
return AccountLockout;
}();
exports.default = AccountLockout;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } var Parse = require('parse/node').Parse; var RestQuery = require('./RestQuery'); // An Auth object tells you who is requesting something and whether // the master key was used. // userObject is a Parse.User and can be null if there's no user. function Auth() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, config = _ref.config, _ref$isMaster = _ref.isMaster, isMaster = _ref$isMaster === undefined ? false : _ref$isMaster, user = _ref.user, installationId = _ref.installationId; this.config = config; this.installationId = installationId; this.isMaster = isMaster; this.user = user; // Assuming a users roles won't change during a single request, we'll // only load them once. this.userRoles = []; this.fetchedRoles = false; this.rolePromise = null; } // Whether this auth could possibly modify the given user id. // It still could be forbidden via ACLs even if this returns true. Auth.prototype.couldUpdateUserId = function (userId) { if (this.isMaster) { return true; } if (this.user && this.user.id === userId) { return true; } return false; }; // A helper to get a master-level Auth object function master(config) { return new Auth({ config: config, isMaster: true }); } // A helper to get a nobody-level Auth object function nobody(config) { return new Auth({ config: config, isMaster: false }); } // Returns a promise that resolves to an Auth object var getAuthForSessionToken = function getAuthForSessionToken() { var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, config = _ref2.config, sessionToken = _ref2.sessionToken, installationId = _ref2.installationId; return config.cacheController.user.get(sessionToken).then(function (userJSON) { if (userJSON) { var cachedUser = Parse.Object.fromJSON(userJSON); return Promise.resolve(new Auth({ config: config, isMaster: false, installationId: installationId, user: cachedUser })); } var restOptions = { limit: 1, include: 'user' }; var query = new RestQuery(config, master(config), '_Session', { sessionToken: sessionToken }, restOptions); return query.execute().then(function (response) { var results = response.results; if (results.length !== 1 || !results[0]['user']) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'invalid session token'); } var now = new Date(), expiresAt = results[0].expiresAt ? new Date(results[0].expiresAt.iso) : undefined; if (expiresAt < now) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Session token is expired.'); } var obj = results[0]['user']; delete obj.password; obj['className'] = '_User'; obj['sessionToken'] = sessionToken; config.cacheController.user.put(sessionToken, obj); var userObject = Parse.Object.fromJSON(obj); return new Auth({ config: config, isMaster: false, installationId: installationId, user: userObject }); }); }); }; var getAuthForLegacySessionToken = function getAuthForLegacySessionToken() { var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, config = _ref3.config, sessionToken = _ref3.sessionToken, installationId = _ref3.installationId; var restOptions = { limit: 1 }; var query = new RestQuery(config, master(config), '_User', { sessionToken: sessionToken }, restOptions); return query.execute().then(function (response) { var results = response.results; if (results.length !== 1) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'invalid legacy session token'); } var obj = results[0]; obj.className = '_User'; var userObject = Parse.Object.fromJSON(obj); return new Auth({ config: config, isMaster: false, installationId: installationId, user: userObject }); }); }; // Returns a promise that resolves to an array of role names Auth.prototype.getUserRoles = function () { if (this.isMaster || !this.user) { return Promise.resolve([]); } if (this.fetchedRoles) { return Promise.resolve(this.userRoles); } if (this.rolePromise) { return this.rolePromise; } this.rolePromise = this._loadRoles(); return this.rolePromise; }; // Iterates through the role tree and compiles a users roles Auth.prototype._loadRoles = function () { var _this = this; var cacheAdapter = this.config.cacheController; return cacheAdapter.role.get(this.user.id).then(function (cachedRoles) { if (cachedRoles != null) { _this.fetchedRoles = true; _this.userRoles = cachedRoles; return Promise.resolve(cachedRoles); } var restWhere = { 'users': { __type: 'Pointer', className: '_User', objectId: _this.user.id } }; // First get the role ids this user is directly a member of var query = new RestQuery(_this.config, master(_this.config), '_Role', restWhere, {}); return query.execute().then(function (response) { var results = response.results; if (!results.length) { _this.userRoles = []; _this.fetchedRoles = true; _this.rolePromise = null; cacheAdapter.role.put(_this.user.id, _this.userRoles); return Promise.resolve(_this.userRoles); } var rolesMap = results.reduce(function (m, r) { m.names.push(r.name); m.ids.push(r.objectId); return m; }, { ids: [], names: [] }); // run the recursive finding return _this._getAllRolesNamesForRoleIds(rolesMap.ids, rolesMap.names).then(function (roleNames) { _this.userRoles = roleNames.map(function (r) { return 'role:' + r; }); _this.fetchedRoles = true; _this.rolePromise = null; cacheAdapter.role.put(_this.user.id, _this.userRoles); return Promise.resolve(_this.userRoles); }); }); }); }; // Given a list of roleIds, find all the parent roles, returns a promise with all names Auth.prototype._getAllRolesNamesForRoleIds = function (roleIDs) { var _this2 = this; var names = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var queriedRoles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var ins = roleIDs.filter(function (roleID) { return queriedRoles[roleID] !== true; }).map(function (roleID) { // mark as queried queriedRoles[roleID] = true; return { __type: 'Pointer', className: '_Role', objectId: roleID }; }); // all roles are accounted for, return the names if (ins.length == 0) { return Promise.resolve([].concat(_toConsumableArray(new Set(names)))); } // Build an OR query across all parentRoles var restWhere = void 0; if (ins.length == 1) { restWhere = { 'roles': ins[0] }; } else { restWhere = { 'roles': { '$in': ins } }; } var query = new RestQuery(this.config, master(this.config), '_Role', restWhere, {}); return query.execute().then(function (response) { var results = response.results; // Nothing found if (!results.length) { return Promise.resolve(names); } // Map the results with all Ids and names var resultMap = results.reduce(function (memo, role) { memo.names.push(role.name); memo.ids.push(role.objectId); return memo; }, { ids: [], names: [] }); // store the new found names names = names.concat(resultMap.names); // find the next ones, circular roles will be cut return _this2._getAllRolesNamesForRoleIds(resultMap.ids, names, queriedRoles); }).then(function (names) { return Promise.resolve([].concat(_toConsumableArray(new Set(names)))); }); }; module.exports = { Auth: Auth, master: master, nobody: nobody, getAuthForSessionToken: getAuthForSessionToken, getAuthForLegacySessionToken: getAuthForLegacySessionToken }; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 1 | 'use strict';
var semver = require('semver');
function compatible(compatibleSDK) {
return function (clientSDK) {
if (typeof clientSDK === 'string') {
clientSDK = fromString(clientSDK);
}
// REST API, or custom SDK
if (!clientSDK) {
return true;
}
var clientVersion = clientSDK.version;
var compatiblityVersion = compatibleSDK[clientSDK.sdk];
return semver.satisfies(clientVersion, compatiblityVersion);
};
}
function supportsForwardDelete(clientSDK) {
return compatible({
js: '>=1.9.0'
})(clientSDK);
}
function fromString(version) {
var versionRE = /([-a-zA-Z]+)([0-9\.]+)/;
var match = version.toLowerCase().match(versionRE);
if (match && match.length === 3) {
return {
sdk: match[1],
version: match[2]
};
}
return undefined;
}
module.exports = {
compatible: compatible,
supportsForwardDelete: supportsForwardDelete,
fromString: fromString
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | 1 1 17 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Config = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); // A Config object provides information about how a specific app is
// configured.
// mount is the URL for the root of the API; includes http, domain, etc.
var _cache = require('./cache');
var _cache2 = _interopRequireDefault(_cache);
var _SchemaCache = require('./Controllers/SchemaCache');
var _SchemaCache2 = _interopRequireDefault(_SchemaCache);
var _DatabaseController = require('./Controllers/DatabaseController');
var _DatabaseController2 = _interopRequireDefault(_DatabaseController);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function removeTrailingSlash(str) {
if (!str) {
return str;
}
if (str.endsWith("/")) {
str = str.substr(0, str.length - 1);
}
return str;
}
var Config = exports.Config = function () {
function Config(applicationId, mount) {
_classCallCheck(this, Config);
var cacheInfo = _cache2.default.get(applicationId);
if (!cacheInfo) {
return;
}
this.applicationId = applicationId;
this.jsonLogs = cacheInfo.jsonLogs;
this.masterKey = cacheInfo.masterKey;
this.clientKey = cacheInfo.clientKey;
this.javascriptKey = cacheInfo.javascriptKey;
this.dotNetKey = cacheInfo.dotNetKey;
this.restAPIKey = cacheInfo.restAPIKey;
this.webhookKey = cacheInfo.webhookKey;
this.fileKey = cacheInfo.fileKey;
this.allowClientClassCreation = cacheInfo.allowClientClassCreation;
this.userSensitiveFields = cacheInfo.userSensitiveFields;
// Create a new DatabaseController per request
if (cacheInfo.databaseController) {
var schemaCache = new _SchemaCache2.default(cacheInfo.cacheController, cacheInfo.schemaCacheTTL, cacheInfo.enableSingleSchemaCache);
this.database = new _DatabaseController2.default(cacheInfo.databaseController.adapter, schemaCache);
}
this.schemaCacheTTL = cacheInfo.schemaCacheTTL;
this.enableSingleSchemaCache = cacheInfo.enableSingleSchemaCache;
this.serverURL = cacheInfo.serverURL;
this.publicServerURL = removeTrailingSlash(cacheInfo.publicServerURL);
this.verifyUserEmails = cacheInfo.verifyUserEmails;
this.preventLoginWithUnverifiedEmail = cacheInfo.preventLoginWithUnverifiedEmail;
this.emailVerifyTokenValidityDuration = cacheInfo.emailVerifyTokenValidityDuration;
this.accountLockout = cacheInfo.accountLockout;
this.passwordPolicy = cacheInfo.passwordPolicy;
this.appName = cacheInfo.appName;
this.analyticsController = cacheInfo.analyticsController;
this.cacheController = cacheInfo.cacheController;
this.hooksController = cacheInfo.hooksController;
this.filesController = cacheInfo.filesController;
this.pushController = cacheInfo.pushController;
this.pushControllerQueue = cacheInfo.pushControllerQueue;
this.pushWorker = cacheInfo.pushWorker;
this.hasPushSupport = cacheInfo.hasPushSupport;
this.loggerController = cacheInfo.loggerController;
this.userController = cacheInfo.userController;
this.authDataManager = cacheInfo.authDataManager;
this.customPages = cacheInfo.customPages || {};
this.mount = removeTrailingSlash(mount);
this.liveQueryController = cacheInfo.liveQueryController;
this.sessionLength = cacheInfo.sessionLength;
this.expireInactiveSessions = cacheInfo.expireInactiveSessions;
this.generateSessionExpiresAt = this.generateSessionExpiresAt.bind(this);
this.generateEmailVerifyTokenExpiresAt = this.generateEmailVerifyTokenExpiresAt.bind(this);
this.revokeSessionOnPasswordReset = cacheInfo.revokeSessionOnPasswordReset;
}
_createClass(Config, [{
key: 'generateEmailVerifyTokenExpiresAt',
value: function generateEmailVerifyTokenExpiresAt() {
if (!this.verifyUserEmails || !this.emailVerifyTokenValidityDuration) {
return undefined;
}
var now = new Date();
return new Date(now.getTime() + this.emailVerifyTokenValidityDuration * 1000);
}
}, {
key: 'generatePasswordResetTokenExpiresAt',
value: function generatePasswordResetTokenExpiresAt() {
if (!this.passwordPolicy || !this.passwordPolicy.resetTokenValidityDuration) {
return undefined;
}
var now = new Date();
return new Date(now.getTime() + this.passwordPolicy.resetTokenValidityDuration * 1000);
}
}, {
key: 'generateSessionExpiresAt',
value: function generateSessionExpiresAt() {
if (!this.expireInactiveSessions) {
return undefined;
}
var now = new Date();
return new Date(now.getTime() + this.sessionLength * 1000);
}
}, {
key: 'mount',
get: function get() {
var mount = this._mount;
if (this.publicServerURL) {
mount = this.publicServerURL;
}
return mount;
},
set: function set(newValue) {
this._mount = newValue;
}
}, {
key: 'invalidLinkURL',
get: function get() {
return this.customPages.invalidLink || this.publicServerURL + '/apps/invalid_link.html';
}
}, {
key: 'verifyEmailSuccessURL',
get: function get() {
return this.customPages.verifyEmailSuccess || this.publicServerURL + '/apps/verify_email_success.html';
}
}, {
key: 'choosePasswordURL',
get: function get() {
return this.customPages.choosePassword || this.publicServerURL + '/apps/choose_password';
}
}, {
key: 'requestResetPasswordURL',
get: function get() {
return this.publicServerURL + '/apps/' + this.applicationId + '/request_password_reset';
}
}, {
key: 'passwordResetSuccessURL',
get: function get() {
return this.customPages.passwordResetSuccess || this.publicServerURL + '/apps/password_reset_success.html';
}
}, {
key: 'parseFrameURL',
get: function get() {
return this.customPages.parseFrameURL;
}
}, {
key: 'verifyEmailURL',
get: function get() {
return this.publicServerURL + '/apps/' + this.applicationId + '/verify_email';
}
}], [{
key: 'validate',
value: function validate(_ref) {
var verifyUserEmails = _ref.verifyUserEmails,
userController = _ref.userController,
appName = _ref.appName,
publicServerURL = _ref.publicServerURL,
revokeSessionOnPasswordReset = _ref.revokeSessionOnPasswordReset,
expireInactiveSessions = _ref.expireInactiveSessions,
sessionLength = _ref.sessionLength,
emailVerifyTokenValidityDuration = _ref.emailVerifyTokenValidityDuration,
accountLockout = _ref.accountLockout,
passwordPolicy = _ref.passwordPolicy;
var emailAdapter = userController.adapter;
if (verifyUserEmails) {
this.validateEmailConfiguration({ emailAdapter: emailAdapter, appName: appName, publicServerURL: publicServerURL, emailVerifyTokenValidityDuration: emailVerifyTokenValidityDuration });
}
this.validateAccountLockoutPolicy(accountLockout);
this.validatePasswordPolicy(passwordPolicy);
if (typeof revokeSessionOnPasswordReset !== 'boolean') {
throw 'revokeSessionOnPasswordReset must be a boolean value';
}
if (publicServerURL) {
if (!publicServerURL.startsWith("http://") && !publicServerURL.startsWith("https://")) {
throw "publicServerURL should be a valid HTTPS URL starting with https://";
}
}
this.validateSessionConfiguration(sessionLength, expireInactiveSessions);
}
}, {
key: 'validateAccountLockoutPolicy',
value: function validateAccountLockoutPolicy(accountLockout) {
if (accountLockout) {
if (typeof accountLockout.duration !== 'number' || accountLockout.duration <= 0 || accountLockout.duration > 99999) {
throw 'Account lockout duration should be greater than 0 and less than 100000';
}
if (!Number.isInteger(accountLockout.threshold) || accountLockout.threshold < 1 || accountLockout.threshold > 999) {
throw 'Account lockout threshold should be an integer greater than 0 and less than 1000';
}
}
}
}, {
key: 'validatePasswordPolicy',
value: function validatePasswordPolicy(passwordPolicy) {
if (passwordPolicy) {
if (passwordPolicy.maxPasswordAge !== undefined && (typeof passwordPolicy.maxPasswordAge !== 'number' || passwordPolicy.maxPasswordAge < 0)) {
throw 'passwordPolicy.maxPasswordAge must be a positive number';
}
if (passwordPolicy.resetTokenValidityDuration !== undefined && (typeof passwordPolicy.resetTokenValidityDuration !== 'number' || passwordPolicy.resetTokenValidityDuration <= 0)) {
throw 'passwordPolicy.resetTokenValidityDuration must be a positive number';
}
if (passwordPolicy.validatorPattern) {
if (typeof passwordPolicy.validatorPattern === 'string') {
passwordPolicy.validatorPattern = new RegExp(passwordPolicy.validatorPattern);
} else if (!(passwordPolicy.validatorPattern instanceof RegExp)) {
throw 'passwordPolicy.validatorPattern must be a regex string or RegExp object.';
}
}
if (passwordPolicy.validatorCallback && typeof passwordPolicy.validatorCallback !== 'function') {
throw 'passwordPolicy.validatorCallback must be a function.';
}
if (passwordPolicy.doNotAllowUsername && typeof passwordPolicy.doNotAllowUsername !== 'boolean') {
throw 'passwordPolicy.doNotAllowUsername must be a boolean value.';
}
if (passwordPolicy.maxPasswordHistory && (!Number.isInteger(passwordPolicy.maxPasswordHistory) || passwordPolicy.maxPasswordHistory <= 0 || passwordPolicy.maxPasswordHistory > 20)) {
throw 'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20';
}
}
}
// if the passwordPolicy.validatorPattern is configured then setup a callback to process the pattern
}, {
key: 'setupPasswordValidator',
value: function setupPasswordValidator(passwordPolicy) {
if (passwordPolicy && passwordPolicy.validatorPattern) {
passwordPolicy.patternValidator = function (value) {
return passwordPolicy.validatorPattern.test(value);
};
}
}
}, {
key: 'validateEmailConfiguration',
value: function validateEmailConfiguration(_ref2) {
var emailAdapter = _ref2.emailAdapter,
appName = _ref2.appName,
publicServerURL = _ref2.publicServerURL,
emailVerifyTokenValidityDuration = _ref2.emailVerifyTokenValidityDuration;
if (!emailAdapter) {
throw 'An emailAdapter is required for e-mail verification and password resets.';
}
if (typeof appName !== 'string') {
throw 'An app name is required for e-mail verification and password resets.';
}
if (typeof publicServerURL !== 'string') {
throw 'A public server url is required for e-mail verification and password resets.';
}
if (emailVerifyTokenValidityDuration) {
if (isNaN(emailVerifyTokenValidityDuration)) {
throw 'Email verify token validity duration must be a valid number.';
} else if (emailVerifyTokenValidityDuration <= 0) {
throw 'Email verify token validity duration must be a value greater than 0.';
}
}
}
}, {
key: 'validateSessionConfiguration',
value: function validateSessionConfiguration(sessionLength, expireInactiveSessions) {
if (expireInactiveSessions) {
if (isNaN(sessionLength)) {
throw 'Session length must be a valid number.';
} else if (sessionLength <= 0) {
throw 'Session length must be a value greater than 0.';
}
}
}
}]);
return Config;
}();
exports.default = Config;
module.exports = Config;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParseMessageQueue = undefined;
var _AdapterLoader = require('./Adapters/AdapterLoader');
var _EventEmitterMQ = require('./Adapters/MessageQueue/EventEmitterMQ');
var ParseMessageQueue = {};
ParseMessageQueue.createPublisher = function (config) {
var adapter = (0, _AdapterLoader.loadAdapter)(config.messageQueueAdapter, _EventEmitterMQ.EventEmitterMQ, config);
if (typeof adapter.createPublisher !== 'function') {
throw 'pubSubAdapter should have createPublisher()';
}
return adapter.createPublisher(config);
};
ParseMessageQueue.createSubscriber = function (config) {
var adapter = (0, _AdapterLoader.loadAdapter)(config.messageQueueAdapter, _EventEmitterMQ.EventEmitterMQ, config);
if (typeof adapter.createSubscriber !== 'function') {
throw 'messageQueueAdapter should have createSubscriber()';
}
return adapter.createSubscriber(config);
};
exports.ParseMessageQueue = ParseMessageQueue;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | 1 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 2 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _defaults = require('./defaults');
var _defaults2 = _interopRequireDefault(_defaults);
var _logger = require('./logger');
var logging = _interopRequireWildcard(_logger);
var _cache = require('./cache');
var _cache2 = _interopRequireDefault(_cache);
var _Config = require('./Config');
var _Config2 = _interopRequireDefault(_Config);
var _PromiseRouter = require('./PromiseRouter');
var _PromiseRouter2 = _interopRequireDefault(_PromiseRouter);
var _requiredParameter = require('./requiredParameter');
var _requiredParameter2 = _interopRequireDefault(_requiredParameter);
var _AnalyticsRouter = require('./Routers/AnalyticsRouter');
var _ClassesRouter = require('./Routers/ClassesRouter');
var _FeaturesRouter = require('./Routers/FeaturesRouter');
var _InMemoryCacheAdapter = require('./Adapters/Cache/InMemoryCacheAdapter');
var _AnalyticsController = require('./Controllers/AnalyticsController');
var _CacheController = require('./Controllers/CacheController');
var _AnalyticsAdapter = require('./Adapters/Analytics/AnalyticsAdapter');
var _WinstonLoggerAdapter = require('./Adapters/Logger/WinstonLoggerAdapter');
var _FilesController = require('./Controllers/FilesController');
var _FilesRouter = require('./Routers/FilesRouter');
var _FunctionsRouter = require('./Routers/FunctionsRouter');
var _GlobalConfigRouter = require('./Routers/GlobalConfigRouter');
var _GridStoreAdapter = require('./Adapters/Files/GridStoreAdapter');
var _HooksController = require('./Controllers/HooksController');
var _HooksRouter = require('./Routers/HooksRouter');
var _IAPValidationRouter = require('./Routers/IAPValidationRouter');
var _InstallationsRouter = require('./Routers/InstallationsRouter');
var _AdapterLoader = require('./Adapters/AdapterLoader');
var _LiveQueryController = require('./Controllers/LiveQueryController');
var _LoggerController = require('./Controllers/LoggerController');
var _LogsRouter = require('./Routers/LogsRouter');
var _ParseLiveQueryServer = require('./LiveQuery/ParseLiveQueryServer');
var _PublicAPIRouter = require('./Routers/PublicAPIRouter');
var _PushController = require('./Controllers/PushController');
var _PushQueue = require('./Push/PushQueue');
var _PushWorker = require('./Push/PushWorker');
var _PushRouter = require('./Routers/PushRouter');
var _CloudCodeRouter = require('./Routers/CloudCodeRouter');
var _RolesRouter = require('./Routers/RolesRouter');
var _SchemasRouter = require('./Routers/SchemasRouter');
var _SessionsRouter = require('./Routers/SessionsRouter');
var _UserController = require('./Controllers/UserController');
var _UsersRouter = require('./Routers/UsersRouter');
var _PurgeRouter = require('./Routers/PurgeRouter');
var _DatabaseController = require('./Controllers/DatabaseController');
var _DatabaseController2 = _interopRequireDefault(_DatabaseController);
var _SchemaCache = require('./Controllers/SchemaCache');
var _SchemaCache2 = _interopRequireDefault(_SchemaCache);
var _parseServerPushAdapter = require('parse-server-push-adapter');
var _parseServerPushAdapter2 = _interopRequireDefault(_parseServerPushAdapter);
var _MongoStorageAdapter = require('./Adapters/Storage/Mongo/MongoStorageAdapter');
var _MongoStorageAdapter2 = _interopRequireDefault(_MongoStorageAdapter);
var _PostgresStorageAdapter = require('./Adapters/Storage/Postgres/PostgresStorageAdapter');
var _PostgresStorageAdapter2 = _interopRequireDefault(_PostgresStorageAdapter);
var _ParseServerRESTController = require('./ParseServerRESTController');
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// ParseServer - open-source compatible API Server for Parse apps
var batch = require('./batch'),
bodyParser = require('body-parser'),
express = require('express'),
middlewares = require('./middlewares'),
Parse = require('parse/node').Parse,
path = require('path'),
url = require('url'),
authDataManager = require('./Adapters/Auth');
// Mutate the Parse object to add the Cloud Code handlers
addParseCloud();
// ParseServer works like a constructor of an express app.
// The args that we understand are:
// "analyticsAdapter": an adapter class for analytics
// "filesAdapter": a class like GridStoreAdapter providing create, get,
// and delete
// "loggerAdapter": a class like WinstonLoggerAdapter providing info, error,
// and query
// "jsonLogs": log as structured JSON objects
// "databaseURI": a uri like mongodb://localhost:27017/dbname to tell us
// what database this Parse API connects to.
// "cloud": relative location to cloud code to require, or a function
// that is given an instance of Parse as a parameter. Use this instance of Parse
// to register your cloud code hooks and functions.
// "appId": the application id to host
// "masterKey": the master key for requests to this app
// "collectionPrefix": optional prefix for database collection names
// "fileKey": optional key from Parse dashboard for supporting older files
// hosted by Parse
// "clientKey": optional key from Parse dashboard
// "dotNetKey": optional key from Parse dashboard
// "restAPIKey": optional key from Parse dashboard
// "webhookKey": optional key from Parse dashboard
// "javascriptKey": optional key from Parse dashboard
// "push": optional key from configure push
// "sessionLength": optional length in seconds for how long Sessions should be valid for
var ParseServer = function () {
function ParseServer(_ref) {
var _ref$appId = _ref.appId,
appId = _ref$appId === undefined ? (0, _requiredParameter2.default)('You must provide an appId!') : _ref$appId,
_ref$masterKey = _ref.masterKey,
masterKey = _ref$masterKey === undefined ? (0, _requiredParameter2.default)('You must provide a masterKey!') : _ref$masterKey,
appName = _ref.appName,
analyticsAdapter = _ref.analyticsAdapter,
filesAdapter = _ref.filesAdapter,
push = _ref.push,
loggerAdapter = _ref.loggerAdapter,
_ref$jsonLogs = _ref.jsonLogs,
jsonLogs = _ref$jsonLogs === undefined ? _defaults2.default.jsonLogs : _ref$jsonLogs,
_ref$logsFolder = _ref.logsFolder,
logsFolder = _ref$logsFolder === undefined ? _defaults2.default.logsFolder : _ref$logsFolder,
_ref$verbose = _ref.verbose,
verbose = _ref$verbose === undefined ? _defaults2.default.verbose : _ref$verbose,
_ref$logLevel = _ref.logLevel,
logLevel = _ref$logLevel === undefined ? _defaults2.default.level : _ref$logLevel,
_ref$silent = _ref.silent,
silent = _ref$silent === undefined ? _defaults2.default.silent : _ref$silent,
_ref$databaseURI = _ref.databaseURI,
databaseURI = _ref$databaseURI === undefined ? _defaults2.default.DefaultMongoURI : _ref$databaseURI,
databaseOptions = _ref.databaseOptions,
databaseAdapter = _ref.databaseAdapter,
cloud = _ref.cloud,
_ref$collectionPrefix = _ref.collectionPrefix,
collectionPrefix = _ref$collectionPrefix === undefined ? '' : _ref$collectionPrefix,
clientKey = _ref.clientKey,
javascriptKey = _ref.javascriptKey,
dotNetKey = _ref.dotNetKey,
restAPIKey = _ref.restAPIKey,
webhookKey = _ref.webhookKey,
fileKey = _ref.fileKey,
_ref$userSensitiveFie = _ref.userSensitiveFields,
userSensitiveFields = _ref$userSensitiveFie === undefined ? [] : _ref$userSensitiveFie,
_ref$enableAnonymousU = _ref.enableAnonymousUsers,
enableAnonymousUsers = _ref$enableAnonymousU === undefined ? _defaults2.default.enableAnonymousUsers : _ref$enableAnonymousU,
_ref$allowClientClass = _ref.allowClientClassCreation,
allowClientClassCreation = _ref$allowClientClass === undefined ? _defaults2.default.allowClientClassCreation : _ref$allowClientClass,
_ref$oauth = _ref.oauth,
oauth = _ref$oauth === undefined ? {} : _ref$oauth,
_ref$auth = _ref.auth,
auth = _ref$auth === undefined ? {} : _ref$auth,
_ref$serverURL = _ref.serverURL,
serverURL = _ref$serverURL === undefined ? (0, _requiredParameter2.default)('You must provide a serverURL!') : _ref$serverURL,
_ref$maxUploadSize = _ref.maxUploadSize,
maxUploadSize = _ref$maxUploadSize === undefined ? _defaults2.default.maxUploadSize : _ref$maxUploadSize,
_ref$verifyUserEmails = _ref.verifyUserEmails,
verifyUserEmails = _ref$verifyUserEmails === undefined ? _defaults2.default.verifyUserEmails : _ref$verifyUserEmails,
_ref$preventLoginWith = _ref.preventLoginWithUnverifiedEmail,
preventLoginWithUnverifiedEmail = _ref$preventLoginWith === undefined ? _defaults2.default.preventLoginWithUnverifiedEmail : _ref$preventLoginWith,
emailVerifyTokenValidityDuration = _ref.emailVerifyTokenValidityDuration,
accountLockout = _ref.accountLockout,
passwordPolicy = _ref.passwordPolicy,
cacheAdapter = _ref.cacheAdapter,
emailAdapter = _ref.emailAdapter,
publicServerURL = _ref.publicServerURL,
_ref$customPages = _ref.customPages,
customPages = _ref$customPages === undefined ? {
invalidLink: undefined,
verifyEmailSuccess: undefined,
choosePassword: undefined,
passwordResetSuccess: undefined
} : _ref$customPages,
_ref$liveQuery = _ref.liveQuery,
liveQuery = _ref$liveQuery === undefined ? {} : _ref$liveQuery,
_ref$sessionLength = _ref.sessionLength,
sessionLength = _ref$sessionLength === undefined ? _defaults2.default.sessionLength : _ref$sessionLength,
_ref$expireInactiveSe = _ref.expireInactiveSessions,
expireInactiveSessions = _ref$expireInactiveSe === undefined ? _defaults2.default.expireInactiveSessions : _ref$expireInactiveSe,
_ref$revokeSessionOnP = _ref.revokeSessionOnPasswordReset,
revokeSessionOnPasswordReset = _ref$revokeSessionOnP === undefined ? _defaults2.default.revokeSessionOnPasswordReset : _ref$revokeSessionOnP,
_ref$schemaCacheTTL = _ref.schemaCacheTTL,
schemaCacheTTL = _ref$schemaCacheTTL === undefined ? _defaults2.default.schemaCacheTTL : _ref$schemaCacheTTL,
_ref$enableSingleSche = _ref.enableSingleSchemaCache,
enableSingleSchemaCache = _ref$enableSingleSche === undefined ? false : _ref$enableSingleSche,
_ref$__indexBuildComp = _ref.__indexBuildCompletionCallbackForTests,
__indexBuildCompletionCallbackForTests = _ref$__indexBuildComp === undefined ? function () {} : _ref$__indexBuildComp;
_classCallCheck(this, ParseServer);
// Initialize the node client SDK automatically
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
Parse.serverURL = serverURL;
if ((databaseOptions || databaseURI && databaseURI != _defaults2.default.DefaultMongoURI || collectionPrefix !== '') && databaseAdapter) {
throw 'You cannot specify both a databaseAdapter and a databaseURI/databaseOptions/collectionPrefix.';
} else if (!databaseAdapter) {
databaseAdapter = this.getDatabaseAdapter(databaseURI, collectionPrefix, databaseOptions);
} else {
databaseAdapter = (0, _AdapterLoader.loadAdapter)(databaseAdapter);
}
if (!filesAdapter && !databaseURI) {
throw 'When using an explicit database adapter, you must also use an explicit filesAdapter.';
}
userSensitiveFields = Array.from(new Set(userSensitiveFields.concat(_defaults2.default.userSensitiveFields, userSensitiveFields)));
var loggerControllerAdapter = (0, _AdapterLoader.loadAdapter)(loggerAdapter, _WinstonLoggerAdapter.WinstonLoggerAdapter, { jsonLogs: jsonLogs, logsFolder: logsFolder, verbose: verbose, logLevel: logLevel, silent: silent });
var loggerController = new _LoggerController.LoggerController(loggerControllerAdapter, appId);
logging.setLogger(loggerController);
var filesControllerAdapter = (0, _AdapterLoader.loadAdapter)(filesAdapter, function () {
return new _GridStoreAdapter.GridStoreAdapter(databaseURI);
});
var filesController = new _FilesController.FilesController(filesControllerAdapter, appId);
var pushOptions = Object.assign({}, push);
var pushQueueOptions = pushOptions.queueOptions || {};
if (pushOptions.queueOptions) {
delete pushOptions.queueOptions;
}
// Pass the push options too as it works with the default
var pushAdapter = (0, _AdapterLoader.loadAdapter)(pushOptions && pushOptions.adapter, _parseServerPushAdapter2.default, pushOptions);
// We pass the options and the base class for the adatper,
// Note that passing an instance would work too
var pushController = new _PushController.PushController();
var hasPushSupport = pushAdapter && push;
var disablePushWorker = pushQueueOptions.disablePushWorker;
var pushControllerQueue = new _PushQueue.PushQueue(pushQueueOptions);
var pushWorker = void 0;
if (!disablePushWorker) {
pushWorker = new _PushWorker.PushWorker(pushAdapter, pushQueueOptions);
}
var emailControllerAdapter = (0, _AdapterLoader.loadAdapter)(emailAdapter);
var userController = new _UserController.UserController(emailControllerAdapter, appId, { verifyUserEmails: verifyUserEmails });
var cacheControllerAdapter = (0, _AdapterLoader.loadAdapter)(cacheAdapter, _InMemoryCacheAdapter.InMemoryCacheAdapter, { appId: appId });
var cacheController = new _CacheController.CacheController(cacheControllerAdapter, appId);
var analyticsControllerAdapter = (0, _AdapterLoader.loadAdapter)(analyticsAdapter, _AnalyticsAdapter.AnalyticsAdapter);
var analyticsController = new _AnalyticsController.AnalyticsController(analyticsControllerAdapter);
var liveQueryController = new _LiveQueryController.LiveQueryController(liveQuery);
var databaseController = new _DatabaseController2.default(databaseAdapter, new _SchemaCache2.default(cacheController, schemaCacheTTL, enableSingleSchemaCache));
var hooksController = new _HooksController.HooksController(appId, databaseController, webhookKey);
var dbInitPromise = databaseController.performInitialization();
if (Object.keys(oauth).length > 0) {
/* eslint-disable no-console */
console.warn('oauth option is deprecated and will be removed in a future release, please use auth option instead');
if (Object.keys(auth).length > 0) {
console.warn('You should use only the auth option.');
}
/* eslint-enable */
}
auth = Object.assign({}, oauth, auth);
_cache2.default.put(appId, {
appId: appId,
masterKey: masterKey,
serverURL: serverURL,
collectionPrefix: collectionPrefix,
clientKey: clientKey,
javascriptKey: javascriptKey,
dotNetKey: dotNetKey,
restAPIKey: restAPIKey,
webhookKey: webhookKey,
fileKey: fileKey,
analyticsController: analyticsController,
cacheController: cacheController,
filesController: filesController,
pushController: pushController,
loggerController: loggerController,
hooksController: hooksController,
userController: userController,
verifyUserEmails: verifyUserEmails,
preventLoginWithUnverifiedEmail: preventLoginWithUnverifiedEmail,
emailVerifyTokenValidityDuration: emailVerifyTokenValidityDuration,
accountLockout: accountLockout,
passwordPolicy: passwordPolicy,
allowClientClassCreation: allowClientClassCreation,
authDataManager: authDataManager(auth, enableAnonymousUsers),
appName: appName,
publicServerURL: publicServerURL,
customPages: customPages,
maxUploadSize: maxUploadSize,
liveQueryController: liveQueryController,
sessionLength: Number(sessionLength),
expireInactiveSessions: expireInactiveSessions,
jsonLogs: jsonLogs,
revokeSessionOnPasswordReset: revokeSessionOnPasswordReset,
databaseController: databaseController,
schemaCacheTTL: schemaCacheTTL,
enableSingleSchemaCache: enableSingleSchemaCache,
userSensitiveFields: userSensitiveFields,
pushWorker: pushWorker,
pushControllerQueue: pushControllerQueue,
hasPushSupport: hasPushSupport
});
_Config2.default.validate(_cache2.default.get(appId));
this.config = _cache2.default.get(appId);
_Config2.default.setupPasswordValidator(this.config.passwordPolicy);
hooksController.load();
// Note: Tests will start to fail if any validation happens after this is called.
if (process.env.TESTING) {
__indexBuildCompletionCallbackForTests(dbInitPromise);
}
if (cloud) {
addParseCloud();
if (typeof cloud === 'function') {
cloud(Parse);
} else if (typeof cloud === 'string') {
require(path.resolve(process.cwd(), cloud));
} else {
throw "argument 'cloud' must either be a string or a function";
}
}
}
_createClass(ParseServer, [{
key: 'getDatabaseAdapter',
value: function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOptions) {
var protocol = void 0;
try {
var parsedURI = url.parse(databaseURI);
protocol = parsedURI.protocol ? parsedURI.protocol.toLowerCase() : null;
} catch (e) {/* */}
switch (protocol) {
case 'postgres:':
return new _PostgresStorageAdapter2.default({
uri: databaseURI,
collectionPrefix: collectionPrefix,
databaseOptions: databaseOptions
});
default:
return new _MongoStorageAdapter2.default({
uri: databaseURI,
collectionPrefix: collectionPrefix,
mongoOptions: databaseOptions
});
}
}
}, {
key: 'app',
get: function get() {
return ParseServer.app(this.config);
}
}], [{
key: 'app',
value: function app(_ref2) {
var _ref2$maxUploadSize = _ref2.maxUploadSize,
maxUploadSize = _ref2$maxUploadSize === undefined ? '20mb' : _ref2$maxUploadSize,
appId = _ref2.appId;
// This app serves the Parse API directly.
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
var api = express();
//api.use("/apps", express.static(__dirname + "/public"));
// File handling needs to be before default middlewares are applied
api.use('/', middlewares.allowCrossDomain, new _FilesRouter.FilesRouter().expressRouter({
maxUploadSize: maxUploadSize
}));
api.use('/health', function (req, res) {
return res.sendStatus(200);
});
api.use('/', bodyParser.urlencoded({ extended: false }), new _PublicAPIRouter.PublicAPIRouter().expressRouter());
api.use(bodyParser.json({ 'type': '*/*', limit: maxUploadSize }));
api.use(middlewares.allowCrossDomain);
api.use(middlewares.allowMethodOverride);
api.use(middlewares.handleParseHeaders);
var appRouter = ParseServer.promiseRouter({ appId: appId });
api.use(appRouter.expressRouter());
api.use(middlewares.handleParseErrors);
//This causes tests to spew some useless warnings, so disable in test
if (!process.env.TESTING) {
process.on('uncaughtException', function (err) {
if (err.code === "EADDRINUSE") {
// user-friendly message for this common error
/* eslint-disable no-console */
console.error('Unable to listen on port ' + err.port + '. The port is already in use.');
/* eslint-enable no-console */
process.exit(0);
} else {
throw err;
}
});
}
if (process.env.PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS === '1') {
Parse.CoreManager.setRESTController((0, _ParseServerRESTController.ParseServerRESTController)(appId, appRouter));
}
return api;
}
}, {
key: 'promiseRouter',
value: function promiseRouter(_ref3) {
var appId = _ref3.appId;
var routers = [new _ClassesRouter.ClassesRouter(), new _UsersRouter.UsersRouter(), new _SessionsRouter.SessionsRouter(), new _RolesRouter.RolesRouter(), new _AnalyticsRouter.AnalyticsRouter(), new _InstallationsRouter.InstallationsRouter(), new _FunctionsRouter.FunctionsRouter(), new _SchemasRouter.SchemasRouter(), new _PushRouter.PushRouter(), new _LogsRouter.LogsRouter(), new _IAPValidationRouter.IAPValidationRouter(), new _FeaturesRouter.FeaturesRouter(), new _GlobalConfigRouter.GlobalConfigRouter(), new _PurgeRouter.PurgeRouter(), new _HooksRouter.HooksRouter(), new _CloudCodeRouter.CloudCodeRouter()];
var routes = routers.reduce(function (memo, router) {
return memo.concat(router.routes);
}, []);
var appRouter = new _PromiseRouter2.default(routes, appId);
batch.mountOnto(appRouter);
return appRouter;
}
}, {
key: 'createLiveQueryServer',
value: function createLiveQueryServer(httpServer, config) {
return new _ParseLiveQueryServer.ParseLiveQueryServer(httpServer, config);
}
}]);
return ParseServer;
}();
function addParseCloud() {
var ParseCloud = require("./cloud-code/Parse.Cloud");
Object.assign(Parse.Cloud, ParseCloud);
global.Parse = Parse;
}
exports.default = ParseServer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var Config = require('./Config');
var Auth = require('./Auth');
var RESTController = require('parse/lib/node/RESTController');
var URL = require('url');
var Parse = require('parse/node');
function getSessionToken(options) {
if (options && typeof options.sessionToken === 'string') {
return Parse.Promise.as(options.sessionToken);
}
return Parse.Promise.as(null);
}
function getAuth() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var config = arguments[1];
var installationId = options.installationId || 'cloud';
if (options.useMasterKey) {
return Parse.Promise.as(new Auth.Auth({ config: config, isMaster: true, installationId: installationId }));
}
return getSessionToken(options).then(function (sessionToken) {
if (sessionToken) {
options.sessionToken = sessionToken;
return Auth.getAuthForSessionToken({
config: config,
sessionToken: sessionToken,
installationId: installationId
});
} else {
return Parse.Promise.as(new Auth.Auth({ config: config, installationId: installationId }));
}
});
}
function ParseServerRESTController(applicationId, router) {
function handleRequest(method, path) {
var data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// Store the arguments, for later use if internal fails
var args = arguments;
var config = new Config(applicationId);
var serverURL = URL.parse(config.serverURL);
if (path.indexOf(serverURL.path) === 0) {
path = path.slice(serverURL.path.length, path.length);
}
if (path[0] !== "/") {
path = "/" + path;
}
if (path === '/batch') {
var promises = data.requests.map(function (request) {
return handleRequest(request.method, request.path, request.body, options).then(function (response) {
return Parse.Promise.as({ success: response });
}, function (error) {
return Parse.Promise.as({ error: { code: error.code, error: error.message } });
});
});
return Parse.Promise.all(promises);
}
var query = void 0;
if (method === 'GET') {
query = data;
}
return new Parse.Promise(function (resolve, reject) {
getAuth(options, config).then(function (auth) {
var request = {
body: data,
config: config,
auth: auth,
info: {
applicationId: applicationId,
sessionToken: options.sessionToken
},
query: query
};
return Promise.resolve().then(function () {
return router.tryRouteRequest(method, path, request);
}).then(function (response) {
resolve(response.response, response.status, response);
}, function (err) {
if (err instanceof Parse.Error && err.code == Parse.Error.INVALID_JSON && err.message == 'cannot route ' + method + ' ' + path) {
RESTController.request.apply(null, args).then(resolve, reject);
} else {
reject(err);
}
});
}, reject);
});
}
return {
request: handleRequest,
ajax: RESTController.ajax
};
}
exports.default = ParseServerRESTController;
exports.ParseServerRESTController = ParseServerRESTController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | 1 1 7 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); // A router that is based on promises rather than req/res/next.
// This is intended to replace the use of express.Router to handle
// subsections of the API surface.
// This will make it easier to have methods like 'batch' that
// themselves use our routing information, without disturbing express
// components that external developers may be modifying.
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _util = require('util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Layer = require('express/lib/router/layer');
function validateParameter(key, value) {
if (key == 'className') {
if (value.match(/_?[A-Za-z][A-Za-z_0-9]*/)) {
return value;
}
} else if (key == 'objectId') {
if (value.match(/[A-Za-z0-9]+/)) {
return value;
}
} else {
return value;
}
}
var PromiseRouter = function () {
// Each entry should be an object with:
// path: the path to route, in express format
// method: the HTTP method that this route handles.
// Must be one of: POST, GET, PUT, DELETE
// handler: a function that takes request, and returns a promise.
// Successful handlers should resolve to an object with fields:
// status: optional. the http status code. defaults to 200
// response: a json object with the content of the response
// location: optional. a location header
function PromiseRouter() {
var routes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var appId = arguments[1];
_classCallCheck(this, PromiseRouter);
this.routes = routes;
this.appId = appId;
this.mountRoutes();
}
// Leave the opportunity to
// subclasses to mount their routes by overriding
_createClass(PromiseRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {}
// Merge the routes into this one
}, {
key: 'merge',
value: function merge(router) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = router.routes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var route = _step.value;
this.routes.push(route);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: 'route',
value: function route(method, path) {
for (var _len = arguments.length, handlers = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
handlers[_key - 2] = arguments[_key];
}
switch (method) {
case 'POST':
case 'GET':
case 'PUT':
case 'DELETE':
break;
default:
throw 'cannot route method: ' + method;
}
var handler = handlers[0];
if (handlers.length > 1) {
handler = function handler(req) {
return handlers.reduce(function (promise, handler) {
return promise.then(function () {
return handler(req);
});
}, Promise.resolve());
};
}
this.routes.push({
path: path,
method: method,
handler: handler,
layer: new Layer(path, null, handler)
});
}
// Returns an object with:
// handler: the handler that should deal with this request
// params: any :-params that got parsed from the path
// Returns undefined if there is no match.
}, {
key: 'match',
value: function match(method, path) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = this.routes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var route = _step2.value;
if (route.method != method) {
continue;
}
var layer = route.layer || new Layer(route.path, null, route.handler);
var match = layer.match(path);
if (match) {
var _ret = function () {
var params = layer.params;
Object.keys(params).forEach(function (key) {
params[key] = validateParameter(key, params[key]);
});
return {
v: { params: params, handler: route.handler }
};
}();
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
// Mount the routes on this router onto an express app (or express router)
}, {
key: 'mountOnto',
value: function mountOnto(expressApp) {
var _this = this;
this.routes.forEach(function (route) {
var method = route.method.toLowerCase();
var handler = makeExpressHandler(_this.appId, route.handler);
expressApp[method].call(expressApp, route.path, handler);
});
return expressApp;
}
}, {
key: 'expressRouter',
value: function expressRouter() {
return this.mountOnto(_express2.default.Router());
}
}, {
key: 'tryRouteRequest',
value: function tryRouteRequest(method, path, request) {
var match = this.match(method, path);
if (!match) {
throw new _node2.default.Error(_node2.default.Error.INVALID_JSON, 'cannot route ' + method + ' ' + path);
}
request.params = match.params;
return new Promise(function (resolve, reject) {
match.handler(request).then(resolve, reject);
});
}
}]);
return PromiseRouter;
}();
// A helper function to make an express handler out of a a promise
// handler.
// Express handlers should never throw; if a promise handler throws we
// just treat it like it resolved to an error.
exports.default = PromiseRouter;
function makeExpressHandler(appId, promiseHandler) {
return function (req, res, next) {
try {
var url = maskSensitiveUrl(req);
var body = Object.assign({}, req.body);
var stringifiedBody = JSON.stringify(body, null, 2);
_logger2.default.verbose('REQUEST for [' + req.method + '] ' + url + ': ' + stringifiedBody, {
method: req.method,
url: url,
headers: req.headers,
body: body
});
promiseHandler(req).then(function (result) {
if (!result.response && !result.location && !result.text) {
_logger2.default.error('the handler did not include a "response" or a "location" field');
throw 'control should not get here';
}
var stringifiedResponse = JSON.stringify(result, null, 2);
_logger2.default.verbose('RESPONSE from [' + req.method + '] ' + url + ': ' + stringifiedResponse, { result: result });
var status = result.status || 200;
res.status(status);
if (result.text) {
res.send(result.text);
return;
}
if (result.location) {
res.set('Location', result.location);
// Override the default expressjs response
// as it double encodes %encoded chars in URL
if (!result.response) {
res.send('Found. Redirecting to ' + result.location);
return;
}
}
if (result.headers) {
Object.keys(result.headers).forEach(function (header) {
res.set(header, result.headers[header]);
});
}
res.json(result.response);
}, function (e) {
_logger2.default.error('Error generating response. ' + (0, _util.inspect)(e), { error: e });
next(e);
});
} catch (e) {
_logger2.default.error('Error handling request: ' + (0, _util.inspect)(e), { error: e });
next(e);
}
};
}
function maskSensitiveUrl(req) {
var maskUrl = req.originalUrl.toString();
var shouldMaskUrl = req.method === 'GET' && req.originalUrl.includes('/login') && !req.originalUrl.includes('classes');
if (shouldMaskUrl) {
maskUrl = _logger2.default.maskSensitiveUrl(maskUrl);
}
return maskUrl;
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; // An object that encapsulates everything we need to run a 'find' // operation, encoded in the REST API format. var SchemaController = require('./Controllers/SchemaController'); var Parse = require('parse/node').Parse; var triggers = require('./triggers'); var AlwaysSelectedKeys = ['objectId', 'createdAt', 'updatedAt']; // restOptions can include: // skip // limit // order // count // include // keys // redirectClassNameForKey function RestQuery(config, auth, className) { var restWhere = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var restOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; var clientSDK = arguments[5]; this.config = config; this.auth = auth; this.className = className; this.restWhere = restWhere; this.restOptions = restOptions; this.clientSDK = clientSDK; this.response = null; this.findOptions = {}; if (!this.auth.isMaster) { this.findOptions.acl = this.auth.user ? [this.auth.user.id] : null; if (this.className == '_Session') { if (!this.findOptions.acl) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'This session token is invalid.'); } this.restWhere = { '$and': [this.restWhere, { 'user': { __type: 'Pointer', className: '_User', objectId: this.auth.user.id } }] }; } } this.doCount = false; // The format for this.include is not the same as the format for the // include option - it's the paths we should include, in order, // stored as arrays, taking into account that we need to include foo // before including foo.bar. Also it should dedupe. // For example, passing an arg of include=foo.bar,foo.baz could lead to // this.include = [['foo'], ['foo', 'baz'], ['foo', 'bar']] this.include = []; // If we have keys, we probably want to force some includes (n-1 level) // See issue: https://github.com/ParsePlatform/parse-server/issues/3185 if (restOptions.hasOwnProperty('keys')) { var keysForInclude = restOptions.keys.split(',').filter(function (key) { // At least 2 components return key.split(".").length > 1; }).map(function (key) { // Slice the last component (a.b.c -> a.b) // Otherwise we'll include one level too much. return key.slice(0, key.lastIndexOf(".")); }).join(','); // Concat the possibly present include string with the one from the keys // Dedup / sorting is handle in 'include' case. if (keysForInclude.length > 0) { if (!restOptions.include || restOptions.include.length == 0) { restOptions.include = keysForInclude; } else { restOptions.include += "," + keysForInclude; } } } for (var option in restOptions) { switch (option) { case 'keys': { var keys = restOptions.keys.split(',').concat(AlwaysSelectedKeys); this.keys = Array.from(new Set(keys)); break; } case 'count': this.doCount = true; break; case 'skip': case 'limit': this.findOptions[option] = restOptions[option]; break; case 'order': var fields = restOptions.order.split(','); this.findOptions.sort = fields.reduce(function (sortMap, field) { field = field.trim(); if (field[0] == '-') { sortMap[field.slice(1)] = -1; } else { sortMap[field] = 1; } return sortMap; }, {}); break; case 'include': { var paths = restOptions.include.split(','); // Load the existing includes (from keys) var pathSet = paths.reduce(function (memo, path) { // Split each paths on . (a.b.c -> [a,b,c]) // reduce to create all paths // ([a,b,c] -> {a: true, 'a.b': true, 'a.b.c': true}) return path.split('.').reduce(function (memo, path, index, parts) { memo[parts.slice(0, index + 1).join('.')] = true; return memo; }, memo); }, {}); this.include = Object.keys(pathSet).map(function (s) { return s.split('.'); }).sort(function (a, b) { return a.length - b.length; // Sort by number of components }); break; } case 'redirectClassNameForKey': this.redirectKey = restOptions.redirectClassNameForKey; this.redirectClassName = null; break; default: throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad option: ' + option); } } } // A convenient method to perform all the steps of processing a query // in order. // Returns a promise for the response - an object with optional keys // 'results' and 'count'. // TODO: consolidate the replaceX functions RestQuery.prototype.execute = function (executeOptions) { var _this = this; return Promise.resolve().then(function () { return _this.buildRestWhere(); }).then(function () { return _this.runFind(executeOptions); }).then(function () { return _this.runCount(); }).then(function () { return _this.handleInclude(); }).then(function () { return _this.runAfterFindTrigger(); }).then(function () { return _this.response; }); }; RestQuery.prototype.buildRestWhere = function () { var _this2 = this; return Promise.resolve().then(function () { return _this2.getUserAndRoleACL(); }).then(function () { return _this2.redirectClassNameForKey(); }).then(function () { return _this2.validateClientClassCreation(); }).then(function () { return _this2.replaceSelect(); }).then(function () { return _this2.replaceDontSelect(); }).then(function () { return _this2.replaceInQuery(); }).then(function () { return _this2.replaceNotInQuery(); }); }; // Uses the Auth object to get the list of roles, adds the user id RestQuery.prototype.getUserAndRoleACL = function () { var _this3 = this; if (this.auth.isMaster || !this.auth.user) { return Promise.resolve(); } return this.auth.getUserRoles().then(function (roles) { // Concat with the roles to prevent duplications on multiple calls var aclSet = new Set([].concat(_this3.findOptions.acl, roles)); _this3.findOptions.acl = Array.from(aclSet); return Promise.resolve(); }); }; // Changes the className if redirectClassNameForKey is set. // Returns a promise. RestQuery.prototype.redirectClassNameForKey = function () { var _this4 = this; if (!this.redirectKey) { return Promise.resolve(); } // We need to change the class name based on the schema return this.config.database.redirectClassNameForKey(this.className, this.redirectKey).then(function (newClassName) { _this4.className = newClassName; _this4.redirectClassName = newClassName; }); }; // Validates this operation against the allowClientClassCreation config. RestQuery.prototype.validateClientClassCreation = function () { var _this5 = this; if (this.config.allowClientClassCreation === false && !this.auth.isMaster && SchemaController.systemClasses.indexOf(this.className) === -1) { return this.config.database.loadSchema().then(function (schemaController) { return schemaController.hasClass(_this5.className); }).then(function (hasClass) { if (hasClass !== true) { throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'This user is not allowed to access ' + 'non-existent class: ' + _this5.className); } }); } else { return Promise.resolve(); } }; function transformInQuery(inQueryObject, className, results) { var values = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = results[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var result = _step.value; values.push({ __type: 'Pointer', className: className, objectId: result.objectId }); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } delete inQueryObject['$inQuery']; if (Array.isArray(inQueryObject['$in'])) { inQueryObject['$in'] = inQueryObject['$in'].concat(values); } else { inQueryObject['$in'] = values; } } // Replaces a $inQuery clause by running the subquery, if there is an // $inQuery clause. // The $inQuery clause turns into an $in with values that are just // pointers to the objects returned in the subquery. RestQuery.prototype.replaceInQuery = function () { var _this6 = this; var inQueryObject = findObjectWithKey(this.restWhere, '$inQuery'); if (!inQueryObject) { return; } // The inQuery value must have precisely two keys - where and className var inQueryValue = inQueryObject['$inQuery']; if (!inQueryValue.where || !inQueryValue.className) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'improper usage of $inQuery'); } var additionalOptions = { redirectClassNameForKey: inQueryValue.redirectClassNameForKey }; var subquery = new RestQuery(this.config, this.auth, inQueryValue.className, inQueryValue.where, additionalOptions); return subquery.execute().then(function (response) { transformInQuery(inQueryObject, subquery.className, response.results); // Recurse to repeat return _this6.replaceInQuery(); }); }; function transformNotInQuery(notInQueryObject, className, results) { var values = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = results[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var result = _step2.value; values.push({ __type: 'Pointer', className: className, objectId: result.objectId }); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } delete notInQueryObject['$notInQuery']; if (Array.isArray(notInQueryObject['$nin'])) { notInQueryObject['$nin'] = notInQueryObject['$nin'].concat(values); } else { notInQueryObject['$nin'] = values; } } // Replaces a $notInQuery clause by running the subquery, if there is an // $notInQuery clause. // The $notInQuery clause turns into a $nin with values that are just // pointers to the objects returned in the subquery. RestQuery.prototype.replaceNotInQuery = function () { var _this7 = this; var notInQueryObject = findObjectWithKey(this.restWhere, '$notInQuery'); if (!notInQueryObject) { return; } // The notInQuery value must have precisely two keys - where and className var notInQueryValue = notInQueryObject['$notInQuery']; if (!notInQueryValue.where || !notInQueryValue.className) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'improper usage of $notInQuery'); } var additionalOptions = { redirectClassNameForKey: notInQueryValue.redirectClassNameForKey }; var subquery = new RestQuery(this.config, this.auth, notInQueryValue.className, notInQueryValue.where, additionalOptions); return subquery.execute().then(function (response) { transformNotInQuery(notInQueryObject, subquery.className, response.results); // Recurse to repeat return _this7.replaceNotInQuery(); }); }; var transformSelect = function transformSelect(selectObject, key, objects) { var values = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = objects[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var result = _step3.value; values.push(result[key]); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } delete selectObject['$select']; if (Array.isArray(selectObject['$in'])) { selectObject['$in'] = selectObject['$in'].concat(values); } else { selectObject['$in'] = values; } }; // Replaces a $select clause by running the subquery, if there is a // $select clause. // The $select clause turns into an $in with values selected out of // the subquery. // Returns a possible-promise. RestQuery.prototype.replaceSelect = function () { var _this8 = this; var selectObject = findObjectWithKey(this.restWhere, '$select'); if (!selectObject) { return; } // The select value must have precisely two keys - query and key var selectValue = selectObject['$select']; // iOS SDK don't send where if not set, let it pass if (!selectValue.query || !selectValue.key || _typeof(selectValue.query) !== 'object' || !selectValue.query.className || Object.keys(selectValue).length !== 2) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'improper usage of $select'); } var additionalOptions = { redirectClassNameForKey: selectValue.query.redirectClassNameForKey }; var subquery = new RestQuery(this.config, this.auth, selectValue.query.className, selectValue.query.where, additionalOptions); return subquery.execute().then(function (response) { transformSelect(selectObject, selectValue.key, response.results); // Keep replacing $select clauses return _this8.replaceSelect(); }); }; var transformDontSelect = function transformDontSelect(dontSelectObject, key, objects) { var values = []; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = objects[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var result = _step4.value; values.push(result[key]); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } delete dontSelectObject['$dontSelect']; if (Array.isArray(dontSelectObject['$nin'])) { dontSelectObject['$nin'] = dontSelectObject['$nin'].concat(values); } else { dontSelectObject['$nin'] = values; } }; // Replaces a $dontSelect clause by running the subquery, if there is a // $dontSelect clause. // The $dontSelect clause turns into an $nin with values selected out of // the subquery. // Returns a possible-promise. RestQuery.prototype.replaceDontSelect = function () { var _this9 = this; var dontSelectObject = findObjectWithKey(this.restWhere, '$dontSelect'); if (!dontSelectObject) { return; } // The dontSelect value must have precisely two keys - query and key var dontSelectValue = dontSelectObject['$dontSelect']; if (!dontSelectValue.query || !dontSelectValue.key || _typeof(dontSelectValue.query) !== 'object' || !dontSelectValue.query.className || Object.keys(dontSelectValue).length !== 2) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'improper usage of $dontSelect'); } var additionalOptions = { redirectClassNameForKey: dontSelectValue.query.redirectClassNameForKey }; var subquery = new RestQuery(this.config, this.auth, dontSelectValue.query.className, dontSelectValue.query.where, additionalOptions); return subquery.execute().then(function (response) { transformDontSelect(dontSelectObject, dontSelectValue.key, response.results); // Keep replacing $dontSelect clauses return _this9.replaceDontSelect(); }); }; var cleanResultOfSensitiveUserInfo = function cleanResultOfSensitiveUserInfo(result, auth, config) { delete result.password; if (auth.isMaster || auth.user && auth.user.id === result.objectId) { return; } var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = config.userSensitiveFields[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var field = _step5.value; delete result[field]; } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } }; var cleanResultAuthData = function cleanResultAuthData(result) { if (result.authData) { Object.keys(result.authData).forEach(function (provider) { if (result.authData[provider] === null) { delete result.authData[provider]; } }); if (Object.keys(result.authData).length == 0) { delete result.authData; } } }; // Returns a promise for whether it was successful. // Populates this.response with an object that only has 'results'. RestQuery.prototype.runFind = function () { var _this10 = this; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (this.findOptions.limit === 0) { this.response = { results: [] }; return Promise.resolve(); } var findOptions = Object.assign({}, this.findOptions); if (this.keys) { findOptions.keys = this.keys.map(function (key) { return key.split('.')[0]; }); } if (options.op) { findOptions.op = options.op; } return this.config.database.find(this.className, this.restWhere, findOptions).then(function (results) { if (_this10.className === '_User') { var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = results[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var result = _step6.value; cleanResultOfSensitiveUserInfo(result, _this10.auth, _this10.config); cleanResultAuthData(result); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } } _this10.config.filesController.expandFilesInObject(_this10.config, results); if (_this10.redirectClassName) { var _iteratorNormalCompletion7 = true; var _didIteratorError7 = false; var _iteratorError7 = undefined; try { for (var _iterator7 = results[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { var r = _step7.value; r.className = _this10.redirectClassName; } } catch (err) { _didIteratorError7 = true; _iteratorError7 = err; } finally { try { if (!_iteratorNormalCompletion7 && _iterator7.return) { _iterator7.return(); } } finally { if (_didIteratorError7) { throw _iteratorError7; } } } } _this10.response = { results: results }; }); }; // Returns a promise for whether it was successful. // Populates this.response.count with the count RestQuery.prototype.runCount = function () { var _this11 = this; if (!this.doCount) { return; } this.findOptions.count = true; delete this.findOptions.skip; delete this.findOptions.limit; return this.config.database.find(this.className, this.restWhere, this.findOptions).then(function (c) { _this11.response.count = c; }); }; // Augments this.response with data at the paths provided in this.include. RestQuery.prototype.handleInclude = function () { var _this12 = this; if (this.include.length == 0) { return; } var pathResponse = includePath(this.config, this.auth, this.response, this.include[0], this.restOptions); if (pathResponse.then) { return pathResponse.then(function (newResponse) { _this12.response = newResponse; _this12.include = _this12.include.slice(1); return _this12.handleInclude(); }); } else if (this.include.length > 0) { this.include = this.include.slice(1); return this.handleInclude(); } return pathResponse; }; //Returns a promise of a processed set of results RestQuery.prototype.runAfterFindTrigger = function () { var _this13 = this; if (!this.response) { return; } // Avoid doing any setup for triggers if there is no 'afterFind' trigger for this class. var hasAfterFindHook = triggers.triggerExists(this.className, triggers.Types.afterFind, this.config.applicationId); if (!hasAfterFindHook) { return Promise.resolve(); } // Run afterFind trigger and set the new results return triggers.maybeRunAfterFindTrigger(triggers.Types.afterFind, this.auth, this.className, this.response.results, this.config).then(function (results) { _this13.response.results = results; }); }; // Adds included values to the response. // Path is a list of field names. // Returns a promise for an augmented response. function includePath(config, auth, response, path) { var restOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; var pointers = findPointers(response.results, path); if (pointers.length == 0) { return response; } var pointersHash = {}; var _iteratorNormalCompletion8 = true; var _didIteratorError8 = false; var _iteratorError8 = undefined; try { for (var _iterator8 = pointers[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { var pointer = _step8.value; if (!pointer) { continue; } var className = pointer.className; // only include the good pointers if (className) { pointersHash[className] = pointersHash[className] || new Set(); pointersHash[className].add(pointer.objectId); } } } catch (err) { _didIteratorError8 = true; _iteratorError8 = err; } finally { try { if (!_iteratorNormalCompletion8 && _iterator8.return) { _iterator8.return(); } } finally { if (_didIteratorError8) { throw _iteratorError8; } } } var includeRestOptions = {}; if (restOptions.keys) { var keys = new Set(restOptions.keys.split(',')); var keySet = Array.from(keys).reduce(function (set, key) { var keyPath = key.split('.'); var i = 0; for (i; i < path.length; i++) { if (path[i] != keyPath[i]) { return set; } } if (i < keyPath.length) { set.add(keyPath[i]); } return set; }, new Set()); if (keySet.size > 0) { includeRestOptions.keys = Array.from(keySet).join(','); } } var queryPromises = Object.keys(pointersHash).map(function (className) { var where = { 'objectId': { '$in': Array.from(pointersHash[className]) } }; var query = new RestQuery(config, auth, className, where, includeRestOptions); return query.execute({ op: 'get' }).then(function (results) { results.className = className; return Promise.resolve(results); }); }); // Get the objects for all these object ids return Promise.all(queryPromises).then(function (responses) { var replace = responses.reduce(function (replace, includeResponse) { var _iteratorNormalCompletion9 = true; var _didIteratorError9 = false; var _iteratorError9 = undefined; try { for (var _iterator9 = includeResponse.results[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) { var obj = _step9.value; obj.__type = 'Object'; obj.className = includeResponse.className; if (obj.className == "_User" && !auth.isMaster) { delete obj.sessionToken; delete obj.authData; } replace[obj.objectId] = obj; } } catch (err) { _didIteratorError9 = true; _iteratorError9 = err; } finally { try { if (!_iteratorNormalCompletion9 && _iterator9.return) { _iterator9.return(); } } finally { if (_didIteratorError9) { throw _iteratorError9; } } } return replace; }, {}); var resp = { results: replacePointers(response.results, path, replace) }; if (response.count) { resp.count = response.count; } return resp; }); } // Object may be a list of REST-format object to find pointers in, or // it may be a single object. // If the path yields things that aren't pointers, this throws an error. // Path is a list of fields to search into. // Returns a list of pointers in REST format. function findPointers(object, path) { if (object instanceof Array) { var answer = []; var _iteratorNormalCompletion10 = true; var _didIteratorError10 = false; var _iteratorError10 = undefined; try { for (var _iterator10 = object[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) { var x = _step10.value; answer = answer.concat(findPointers(x, path)); } } catch (err) { _didIteratorError10 = true; _iteratorError10 = err; } finally { try { if (!_iteratorNormalCompletion10 && _iterator10.return) { _iterator10.return(); } } finally { if (_didIteratorError10) { throw _iteratorError10; } } } return answer; } if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) !== 'object' || !object) { return []; } if (path.length == 0) { if (object === null || object.__type == 'Pointer') { return [object]; } return []; } var subobject = object[path[0]]; if (!subobject) { return []; } return findPointers(subobject, path.slice(1)); } // Object may be a list of REST-format objects to replace pointers // in, or it may be a single object. // Path is a list of fields to search into. // replace is a map from object id -> object. // Returns something analogous to object, but with the appropriate // pointers inflated. function replacePointers(object, path, replace) { if (object instanceof Array) { return object.map(function (obj) { return replacePointers(obj, path, replace); }).filter(function (obj) { return typeof obj !== 'undefined'; }); } if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) !== 'object' || !object) { return object; } if (path.length === 0) { if (object && object.__type === 'Pointer') { return replace[object.objectId]; } return object; } var subobject = object[path[0]]; if (!subobject) { return object; } var newsub = replacePointers(subobject, path.slice(1), replace); var answer = {}; for (var key in object) { if (key == path[0]) { answer[key] = newsub; } else { answer[key] = object[key]; } } return answer; } // Finds a subobject that has the given key, if there is one. // Returns undefined otherwise. function findObjectWithKey(root, key) { if ((typeof root === 'undefined' ? 'undefined' : _typeof(root)) !== 'object') { return; } if (root instanceof Array) { var _iteratorNormalCompletion11 = true; var _didIteratorError11 = false; var _iteratorError11 = undefined; try { for (var _iterator11 = root[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) { var item = _step11.value; var answer = findObjectWithKey(item, key); if (answer) { return answer; } } } catch (err) { _didIteratorError11 = true; _iteratorError11 = err; } finally { try { if (!_iteratorNormalCompletion11 && _iterator11.return) { _iterator11.return(); } } finally { if (_didIteratorError11) { throw _iteratorError11; } } } } if (root && root[key]) { return root; } for (var subkey in root) { var _answer = findObjectWithKey(root[subkey], key); if (_answer) { return _answer; } } } module.exports = RestQuery; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _RestQuery = require('./RestQuery');
var _RestQuery2 = _interopRequireDefault(_RestQuery);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// A RestWrite encapsulates everything we need to run an operation
// that writes to the database.
// This could be either a "create" or an "update".
var SchemaController = require('./Controllers/SchemaController');
var deepcopy = require('deepcopy');
var Auth = require('./Auth');
var cryptoUtils = require('./cryptoUtils');
var passwordCrypto = require('./password');
var Parse = require('parse/node');
var triggers = require('./triggers');
var ClientSDK = require('./ClientSDK');
// query and data are both provided in REST API format. So data
// types are encoded by plain old objects.
// If query is null, this is a "create" and the data in data should be
// created.
// Otherwise this is an "update" - the object matching the query
// should get updated with data.
// RestWrite will handle objectId, createdAt, and updatedAt for
// everything. It also knows to use triggers and special modifications
// for the _User class.
function RestWrite(config, auth, className, query, data, originalData, clientSDK) {
this.config = config;
this.auth = auth;
this.className = className;
this.clientSDK = clientSDK;
this.storage = {};
this.runOptions = {};
if (!query && data.objectId) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'objectId is an invalid field name.');
}
// When the operation is complete, this.response may have several
// fields.
// response: the actual data to be returned
// status: the http status code. if not present, treated like a 200
// location: the location header. if not present, no location header
this.response = null;
// Processing this operation may mutate our data, so we operate on a
// copy
this.query = deepcopy(query);
this.data = deepcopy(data);
// We never change originalData, so we do not need a deep copy
this.originalData = originalData;
// The timestamp we'll use for this whole operation
this.updatedAt = Parse._encode(new Date()).iso;
}
// A convenient method to perform all the steps of processing the
// write, in order.
// Returns a promise for a {response, status, location} object.
// status and location are optional.
RestWrite.prototype.execute = function () {
var _this = this;
return Promise.resolve().then(function () {
return _this.getUserAndRoleACL();
}).then(function () {
return _this.validateClientClassCreation();
}).then(function () {
return _this.handleInstallation();
}).then(function () {
return _this.handleSession();
}).then(function () {
return _this.validateAuthData();
}).then(function () {
return _this.runBeforeTrigger();
}).then(function () {
return _this.validateSchema();
}).then(function () {
return _this.setRequiredFieldsIfNeeded();
}).then(function () {
return _this.transformUser();
}).then(function () {
return _this.expandFilesForExistingObjects();
}).then(function () {
return _this.runDatabaseOperation();
}).then(function () {
return _this.createSessionTokenIfNeeded();
}).then(function () {
return _this.handleFollowup();
}).then(function () {
return _this.runAfterTrigger();
}).then(function () {
return _this.cleanUserAuthData();
}).then(function () {
return _this.response;
});
};
// Uses the Auth object to get the list of roles, adds the user id
RestWrite.prototype.getUserAndRoleACL = function () {
var _this2 = this;
if (this.auth.isMaster) {
return Promise.resolve();
}
this.runOptions.acl = ['*'];
if (this.auth.user) {
return this.auth.getUserRoles().then(function (roles) {
roles.push(_this2.auth.user.id);
_this2.runOptions.acl = _this2.runOptions.acl.concat(roles);
return;
});
} else {
return Promise.resolve();
}
};
// Validates this operation against the allowClientClassCreation config.
RestWrite.prototype.validateClientClassCreation = function () {
var _this3 = this;
if (this.config.allowClientClassCreation === false && !this.auth.isMaster && SchemaController.systemClasses.indexOf(this.className) === -1) {
return this.config.database.loadSchema().then(function (schemaController) {
return schemaController.hasClass(_this3.className);
}).then(function (hasClass) {
if (hasClass !== true) {
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'This user is not allowed to access ' + 'non-existent class: ' + _this3.className);
}
});
} else {
return Promise.resolve();
}
};
// Validates this operation against the schema.
RestWrite.prototype.validateSchema = function () {
return this.config.database.validateObject(this.className, this.data, this.query, this.runOptions);
};
// Runs any beforeSave triggers against this operation.
// Any change leads to our data being mutated.
RestWrite.prototype.runBeforeTrigger = function () {
var _this4 = this;
if (this.response) {
return;
}
// Avoid doing any setup for triggers if there is no 'beforeSave' trigger for this class.
if (!triggers.triggerExists(this.className, triggers.Types.beforeSave, this.config.applicationId)) {
return Promise.resolve();
}
// Cloud code gets a bit of extra data for its objects
var extraData = { className: this.className };
if (this.query && this.query.objectId) {
extraData.objectId = this.query.objectId;
}
var originalObject = null;
var updatedObject = triggers.inflate(extraData, this.originalData);
if (this.query && this.query.objectId) {
// This is an update for existing object.
originalObject = triggers.inflate(extraData, this.originalData);
}
updatedObject.set(this.sanitizedData());
return Promise.resolve().then(function () {
return triggers.maybeRunTrigger(triggers.Types.beforeSave, _this4.auth, updatedObject, originalObject, _this4.config);
}).then(function (response) {
if (response && response.object) {
_this4.storage.fieldsChangedByTrigger = _lodash2.default.reduce(response.object, function (result, value, key) {
if (!_lodash2.default.isEqual(_this4.data[key], value)) {
result.push(key);
}
return result;
}, []);
_this4.data = response.object;
// We should delete the objectId for an update write
if (_this4.query && _this4.query.objectId) {
delete _this4.data.objectId;
}
}
});
};
RestWrite.prototype.setRequiredFieldsIfNeeded = function () {
if (this.data) {
// Add default fields
this.data.updatedAt = this.updatedAt;
if (!this.query) {
this.data.createdAt = this.updatedAt;
// Only assign new objectId if we are creating new object
if (!this.data.objectId) {
this.data.objectId = cryptoUtils.newObjectId();
}
}
}
return Promise.resolve();
};
// Transforms auth data for a user object.
// Does nothing if this isn't a user object.
// Returns a promise for when we're done if it can't finish this tick.
RestWrite.prototype.validateAuthData = function () {
if (this.className !== '_User') {
return;
}
if (!this.query && !this.data.authData) {
if (typeof this.data.username !== 'string' || _lodash2.default.isEmpty(this.data.username)) {
throw new Parse.Error(Parse.Error.USERNAME_MISSING, 'bad or missing username');
}
if (typeof this.data.password !== 'string' || _lodash2.default.isEmpty(this.data.password)) {
throw new Parse.Error(Parse.Error.PASSWORD_MISSING, 'password is required');
}
}
if (!this.data.authData || !Object.keys(this.data.authData).length) {
return;
}
var authData = this.data.authData;
var providers = Object.keys(authData);
if (providers.length > 0) {
var canHandleAuthData = providers.reduce(function (canHandle, provider) {
var providerAuthData = authData[provider];
var hasToken = providerAuthData && providerAuthData.id;
return canHandle && (hasToken || providerAuthData == null);
}, true);
if (canHandleAuthData) {
return this.handleAuthData(authData);
}
}
throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE, 'This authentication method is unsupported.');
};
RestWrite.prototype.handleAuthDataValidation = function (authData) {
var _this5 = this;
var validations = Object.keys(authData).map(function (provider) {
if (authData[provider] === null) {
return Promise.resolve();
}
var validateAuthData = _this5.config.authDataManager.getValidatorForProvider(provider);
if (!validateAuthData) {
throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE, 'This authentication method is unsupported.');
}
return validateAuthData(authData[provider]);
});
return Promise.all(validations);
};
RestWrite.prototype.findUsersWithAuthData = function (authData) {
var providers = Object.keys(authData);
var query = providers.reduce(function (memo, provider) {
if (!authData[provider]) {
return memo;
}
var queryKey = 'authData.' + provider + '.id';
var query = {};
query[queryKey] = authData[provider].id;
memo.push(query);
return memo;
}, []).filter(function (q) {
return typeof q !== 'undefined';
});
var findPromise = Promise.resolve([]);
if (query.length > 0) {
findPromise = this.config.database.find(this.className, { '$or': query }, {});
}
return findPromise;
};
RestWrite.prototype.handleAuthData = function (authData) {
var _this6 = this;
var results = void 0;
return this.handleAuthDataValidation(authData).then(function () {
return _this6.findUsersWithAuthData(authData);
}).then(function (r) {
results = r;
if (results.length > 1) {
// More than 1 user with the passed id's
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED, 'this auth is already used');
}
_this6.storage['authProvider'] = Object.keys(authData).join(',');
if (results.length > 0) {
if (!_this6.query) {
// Login with auth data
delete results[0].password;
var userResult = results[0];
// need to set the objectId first otherwise location has trailing undefined
_this6.data.objectId = userResult.objectId;
// Determine if authData was updated
var mutatedAuthData = {};
Object.keys(authData).forEach(function (provider) {
var providerData = authData[provider];
var userAuthData = userResult.authData[provider];
if (!_lodash2.default.isEqual(providerData, userAuthData)) {
mutatedAuthData[provider] = providerData;
}
});
_this6.response = {
response: userResult,
location: _this6.location()
};
// We have authData that is updated on login
// that can happen when token are refreshed,
// We should update the token and let the user in
if (Object.keys(mutatedAuthData).length > 0) {
// Assign the new authData in the response
Object.keys(mutatedAuthData).forEach(function (provider) {
_this6.response.response.authData[provider] = mutatedAuthData[provider];
});
// Run the DB update directly, as 'master'
// Just update the authData part
return _this6.config.database.update(_this6.className, { objectId: _this6.data.objectId }, { authData: mutatedAuthData }, {});
}
return;
} else if (_this6.query && _this6.query.objectId) {
// Trying to update auth data but users
// are different
if (results[0].objectId !== _this6.query.objectId) {
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED, 'this auth is already used');
}
}
}
return;
});
};
// The non-third-party parts of User transformation
RestWrite.prototype.transformUser = function () {
var _this7 = this;
var promise = Promise.resolve();
if (this.className !== '_User') {
return promise;
}
if (this.query) {
// If we're updating a _User object, we need to clear out the cache for that user. Find all their
// session tokens, and remove them from the cache.
promise = new _RestQuery2.default(this.config, Auth.master(this.config), '_Session', {
user: {
__type: "Pointer",
className: "_User",
objectId: this.objectId()
}
}).execute().then(function (results) {
results.results.forEach(function (session) {
return _this7.config.cacheController.user.del(session.sessionToken);
});
});
}
return promise.then(function () {
// Transform the password
if (_this7.data.password === undefined) {
// ignore only if undefined. should proceed if empty ('')
return Promise.resolve();
}
if (_this7.query && !_this7.auth.isMaster) {
_this7.storage['clearSessions'] = true;
_this7.storage['generateNewSession'] = true;
}
return _this7._validatePasswordPolicy().then(function () {
return passwordCrypto.hash(_this7.data.password).then(function (hashedPassword) {
_this7.data._hashed_password = hashedPassword;
delete _this7.data.password;
});
});
}).then(function () {
return _this7._validateUserName();
}).then(function () {
return _this7._validateEmail();
});
};
RestWrite.prototype._validateUserName = function () {
// Check for username uniqueness
if (!this.data.username) {
if (!this.query) {
this.data.username = cryptoUtils.randomString(25);
this.responseShouldHaveUsername = true;
}
return Promise.resolve();
}
// We need to a find to check for duplicate username in case they are missing the unique index on usernames
// TODO: Check if there is a unique index, and if so, skip this query.
return this.config.database.find(this.className, { username: this.data.username, objectId: { '$ne': this.objectId() } }, { limit: 1 }).then(function (results) {
if (results.length > 0) {
throw new Parse.Error(Parse.Error.USERNAME_TAKEN, 'Account already exists for this username.');
}
return;
});
};
RestWrite.prototype._validateEmail = function () {
var _this8 = this;
if (!this.data.email || this.data.email.__op === 'Delete') {
return Promise.resolve();
}
// Validate basic email address format
if (!this.data.email.match(/^.+@.+$/)) {
return Promise.reject(new Parse.Error(Parse.Error.INVALID_EMAIL_ADDRESS, 'Email address format is invalid.'));
}
// Same problem for email as above for username
return this.config.database.find(this.className, { email: this.data.email, objectId: { '$ne': this.objectId() } }, { limit: 1 }).then(function (results) {
if (results.length > 0) {
throw new Parse.Error(Parse.Error.EMAIL_TAKEN, 'Account already exists for this email address.');
}
// We updated the email, send a new validation
_this8.storage['sendVerificationEmail'] = true;
_this8.config.userController.setEmailVerifyToken(_this8.data);
});
};
RestWrite.prototype._validatePasswordPolicy = function () {
var _this9 = this;
if (!this.config.passwordPolicy) return Promise.resolve();
return this._validatePasswordRequirements().then(function () {
return _this9._validatePasswordHistory();
});
};
RestWrite.prototype._validatePasswordRequirements = function () {
var _this10 = this;
// check if the password conforms to the defined password policy if configured
var policyError = 'Password does not meet the Password Policy requirements.';
// check whether the password meets the password strength requirements
if (this.config.passwordPolicy.patternValidator && !this.config.passwordPolicy.patternValidator(this.data.password) || this.config.passwordPolicy.validatorCallback && !this.config.passwordPolicy.validatorCallback(this.data.password)) {
return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, policyError));
}
// check whether password contain username
if (this.config.passwordPolicy.doNotAllowUsername === true) {
if (this.data.username) {
// username is not passed during password reset
if (this.data.password.indexOf(this.data.username) >= 0) return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, policyError));
} else {
// retrieve the User object using objectId during password reset
return this.config.database.find('_User', { objectId: this.objectId() }).then(function (results) {
if (results.length != 1) {
throw undefined;
}
if (_this10.data.password.indexOf(results[0].username) >= 0) return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, policyError));
return Promise.resolve();
});
}
}
return Promise.resolve();
};
RestWrite.prototype._validatePasswordHistory = function () {
var _this11 = this;
// check whether password is repeating from specified history
if (this.query && this.config.passwordPolicy.maxPasswordHistory) {
return this.config.database.find('_User', { objectId: this.objectId() }, { keys: ["_password_history", "_hashed_password"] }).then(function (results) {
if (results.length != 1) {
throw undefined;
}
var user = results[0];
var oldPasswords = [];
if (user._password_history) oldPasswords = _lodash2.default.take(user._password_history, _this11.config.passwordPolicy.maxPasswordHistory - 1);
oldPasswords.push(user.password);
var newPassword = _this11.data.password;
// compare the new password hash with all old password hashes
var promises = oldPasswords.map(function (hash) {
return passwordCrypto.compare(newPassword, hash).then(function (result) {
if (result) // reject if there is a match
return Promise.reject("REPEAT_PASSWORD");
return Promise.resolve();
});
});
// wait for all comparisons to complete
return Promise.all(promises).then(function () {
return Promise.resolve();
}).catch(function (err) {
if (err === "REPEAT_PASSWORD") // a match was found
return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, 'New password should not be the same as last ' + _this11.config.passwordPolicy.maxPasswordHistory + ' passwords.'));
throw err;
});
});
}
return Promise.resolve();
};
RestWrite.prototype.createSessionTokenIfNeeded = function () {
if (this.className !== '_User') {
return;
}
if (this.query) {
return;
}
return this.createSessionToken();
};
RestWrite.prototype.createSessionToken = function () {
// cloud installationId from Cloud Code,
// never create session tokens from there.
if (this.auth.installationId && this.auth.installationId === 'cloud') {
return;
}
var token = 'r:' + cryptoUtils.newToken();
var expiresAt = this.config.generateSessionExpiresAt();
var sessionData = {
sessionToken: token,
user: {
__type: 'Pointer',
className: '_User',
objectId: this.objectId()
},
createdWith: {
'action': 'signup',
'authProvider': this.storage['authProvider'] || 'password'
},
restricted: false,
installationId: this.auth.installationId,
expiresAt: Parse._encode(expiresAt)
};
if (this.response && this.response.response) {
this.response.response.sessionToken = token;
}
var create = new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData);
return create.execute();
};
// Handles any followup logic
RestWrite.prototype.handleFollowup = function () {
if (this.storage && this.storage['clearSessions'] && this.config.revokeSessionOnPasswordReset) {
var sessionQuery = {
user: {
__type: 'Pointer',
className: '_User',
objectId: this.objectId()
}
};
delete this.storage['clearSessions'];
return this.config.database.destroy('_Session', sessionQuery).then(this.handleFollowup.bind(this));
}
if (this.storage && this.storage['generateNewSession']) {
delete this.storage['generateNewSession'];
return this.createSessionToken().then(this.handleFollowup.bind(this));
}
if (this.storage && this.storage['sendVerificationEmail']) {
delete this.storage['sendVerificationEmail'];
// Fire and forget!
this.config.userController.sendVerificationEmail(this.data);
return this.handleFollowup.bind(this);
}
};
// Handles the _Session class specialness.
// Does nothing if this isn't an installation object.
RestWrite.prototype.handleSession = function () {
var _this12 = this;
if (this.response || this.className !== '_Session') {
return;
}
if (!this.auth.user && !this.auth.isMaster) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Session token required.');
}
// TODO: Verify proper error to throw
if (this.data.ACL) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Cannot set ' + 'ACL on a Session.');
}
if (!this.query && !this.auth.isMaster) {
var token = 'r:' + cryptoUtils.newToken();
var expiresAt = this.config.generateSessionExpiresAt();
var sessionData = {
sessionToken: token,
user: {
__type: 'Pointer',
className: '_User',
objectId: this.auth.user.id
},
createdWith: {
'action': 'create'
},
restricted: true,
expiresAt: Parse._encode(expiresAt)
};
for (var key in this.data) {
if (key == 'objectId') {
continue;
}
sessionData[key] = this.data[key];
}
var create = new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData);
return create.execute().then(function (results) {
if (!results.response) {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Error creating session.');
}
sessionData['objectId'] = results.response['objectId'];
_this12.response = {
status: 201,
location: results.location,
response: sessionData
};
});
}
};
// Handles the _Installation class specialness.
// Does nothing if this isn't an installation object.
// If an installation is found, this can mutate this.query and turn a create
// into an update.
// Returns a promise for when we're done if it can't finish this tick.
RestWrite.prototype.handleInstallation = function () {
var _this13 = this;
if (this.response || this.className !== '_Installation') {
return;
}
if (!this.query && !this.data.deviceToken && !this.data.installationId && !this.auth.installationId) {
throw new Parse.Error(135, 'at least one ID field (deviceToken, installationId) ' + 'must be specified in this operation');
}
// If the device token is 64 characters long, we assume it is for iOS
// and lowercase it.
if (this.data.deviceToken && this.data.deviceToken.length == 64) {
this.data.deviceToken = this.data.deviceToken.toLowerCase();
}
// We lowercase the installationId if present
if (this.data.installationId) {
this.data.installationId = this.data.installationId.toLowerCase();
}
var installationId = this.data.installationId;
// If data.installationId is not set and we're not master, we can lookup in auth
if (!installationId && !this.auth.isMaster) {
installationId = this.auth.installationId;
}
if (installationId) {
installationId = installationId.toLowerCase();
}
// Updating _Installation but not updating anything critical
if (this.query && !this.data.deviceToken && !installationId && !this.data.deviceType) {
return;
}
var promise = Promise.resolve();
var idMatch; // Will be a match on either objectId or installationId
var objectIdMatch;
var installationIdMatch;
var deviceTokenMatches = [];
// Instead of issuing 3 reads, let's do it with one OR.
var orQueries = [];
if (this.query && this.query.objectId) {
orQueries.push({
objectId: this.query.objectId
});
}
if (installationId) {
orQueries.push({
'installationId': installationId
});
}
if (this.data.deviceToken) {
orQueries.push({ 'deviceToken': this.data.deviceToken });
}
if (orQueries.length == 0) {
return;
}
promise = promise.then(function () {
return _this13.config.database.find('_Installation', {
'$or': orQueries
}, {});
}).then(function (results) {
results.forEach(function (result) {
if (_this13.query && _this13.query.objectId && result.objectId == _this13.query.objectId) {
objectIdMatch = result;
}
if (result.installationId == installationId) {
installationIdMatch = result;
}
if (result.deviceToken == _this13.data.deviceToken) {
deviceTokenMatches.push(result);
}
});
// Sanity checks when running a query
if (_this13.query && _this13.query.objectId) {
if (!objectIdMatch) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found for update.');
}
if (_this13.data.installationId && objectIdMatch.installationId && _this13.data.installationId !== objectIdMatch.installationId) {
throw new Parse.Error(136, 'installationId may not be changed in this ' + 'operation');
}
if (_this13.data.deviceToken && objectIdMatch.deviceToken && _this13.data.deviceToken !== objectIdMatch.deviceToken && !_this13.data.installationId && !objectIdMatch.installationId) {
throw new Parse.Error(136, 'deviceToken may not be changed in this ' + 'operation');
}
if (_this13.data.deviceType && _this13.data.deviceType && _this13.data.deviceType !== objectIdMatch.deviceType) {
throw new Parse.Error(136, 'deviceType may not be changed in this ' + 'operation');
}
}
if (_this13.query && _this13.query.objectId && objectIdMatch) {
idMatch = objectIdMatch;
}
if (installationId && installationIdMatch) {
idMatch = installationIdMatch;
}
// need to specify deviceType only if it's new
if (!_this13.query && !_this13.data.deviceType && !idMatch) {
throw new Parse.Error(135, 'deviceType must be specified in this operation');
}
}).then(function () {
if (!idMatch) {
if (!deviceTokenMatches.length) {
return;
} else if (deviceTokenMatches.length == 1 && (!deviceTokenMatches[0]['installationId'] || !installationId)) {
// Single match on device token but none on installationId, and either
// the passed object or the match is missing an installationId, so we
// can just return the match.
return deviceTokenMatches[0]['objectId'];
} else if (!_this13.data.installationId) {
throw new Parse.Error(132, 'Must specify installationId when deviceToken ' + 'matches multiple Installation objects');
} else {
// Multiple device token matches and we specified an installation ID,
// or a single match where both the passed and matching objects have
// an installation ID. Try cleaning out old installations that match
// the deviceToken, and return nil to signal that a new object should
// be created.
var delQuery = {
'deviceToken': _this13.data.deviceToken,
'installationId': {
'$ne': installationId
}
};
if (_this13.data.appIdentifier) {
delQuery['appIdentifier'] = _this13.data.appIdentifier;
}
_this13.config.database.destroy('_Installation', delQuery);
return;
}
} else {
if (deviceTokenMatches.length == 1 && !deviceTokenMatches[0]['installationId']) {
// Exactly one device token match and it doesn't have an installation
// ID. This is the one case where we want to merge with the existing
// object.
var _delQuery = { objectId: idMatch.objectId };
return _this13.config.database.destroy('_Installation', _delQuery).then(function () {
return deviceTokenMatches[0]['objectId'];
});
} else {
if (_this13.data.deviceToken && idMatch.deviceToken != _this13.data.deviceToken) {
// We're setting the device token on an existing installation, so
// we should try cleaning out old installations that match this
// device token.
var _delQuery2 = {
'deviceToken': _this13.data.deviceToken
};
// We have a unique install Id, use that to preserve
// the interesting installation
if (_this13.data.installationId) {
_delQuery2['installationId'] = {
'$ne': _this13.data.installationId
};
} else if (idMatch.objectId && _this13.data.objectId && idMatch.objectId == _this13.data.objectId) {
// we passed an objectId, preserve that instalation
_delQuery2['objectId'] = {
'$ne': idMatch.objectId
};
} else {
// What to do here? can't really clean up everything...
return idMatch.objectId;
}
if (_this13.data.appIdentifier) {
_delQuery2['appIdentifier'] = _this13.data.appIdentifier;
}
_this13.config.database.destroy('_Installation', _delQuery2);
}
// In non-merge scenarios, just return the installation match id
return idMatch.objectId;
}
}
}).then(function (objId) {
if (objId) {
_this13.query = { objectId: objId };
delete _this13.data.objectId;
delete _this13.data.createdAt;
}
// TODO: Validate ops (add/remove on channels, $inc on badge, etc.)
});
return promise;
};
// If we short-circuted the object response - then we need to make sure we expand all the files,
// since this might not have a query, meaning it won't return the full result back.
// TODO: (nlutsenko) This should die when we move to per-class based controllers on _Session/_User
RestWrite.prototype.expandFilesForExistingObjects = function () {
// Check whether we have a short-circuited response - only then run expansion.
if (this.response && this.response.response) {
this.config.filesController.expandFilesInObject(this.config, this.response.response);
}
};
RestWrite.prototype.runDatabaseOperation = function () {
var _this14 = this;
if (this.response) {
return;
}
if (this.className === '_Role') {
this.config.cacheController.role.clear();
}
if (this.className === '_User' && this.query && !this.auth.couldUpdateUserId(this.query.objectId)) {
throw new Parse.Error(Parse.Error.SESSION_MISSING, 'Cannot modify user ' + this.query.objectId + '.');
}
if (this.className === '_Product' && this.data.download) {
this.data.downloadName = this.data.download.name;
}
// TODO: Add better detection for ACL, ensuring a user can't be locked from
// their own user record.
if (this.data.ACL && this.data.ACL['*unresolved']) {
throw new Parse.Error(Parse.Error.INVALID_ACL, 'Invalid ACL.');
}
if (this.query) {
// Force the user to not lockout
// Matched with parse.com
if (this.className === '_User' && this.data.ACL) {
this.data.ACL[this.query.objectId] = { read: true, write: true };
}
// update password timestamp if user password is being changed
if (this.className === '_User' && this.data._hashed_password && this.config.passwordPolicy && this.config.passwordPolicy.maxPasswordAge) {
this.data._password_changed_at = Parse._encode(new Date());
}
// Ignore createdAt when update
delete this.data.createdAt;
var defer = Promise.resolve();
// if password history is enabled then save the current password to history
if (this.className === '_User' && this.data._hashed_password && this.config.passwordPolicy && this.config.passwordPolicy.maxPasswordHistory) {
defer = this.config.database.find('_User', { objectId: this.objectId() }, { keys: ["_password_history", "_hashed_password"] }).then(function (results) {
if (results.length != 1) {
throw undefined;
}
var user = results[0];
var oldPasswords = [];
if (user._password_history) {
oldPasswords = _lodash2.default.take(user._password_history, _this14.config.passwordPolicy.maxPasswordHistory);
}
//n-1 passwords go into history including last password
while (oldPasswords.length > _this14.config.passwordPolicy.maxPasswordHistory - 2) {
oldPasswords.shift();
}
oldPasswords.push(user.password);
_this14.data._password_history = oldPasswords;
});
}
return defer.then(function () {
// Run an update
return _this14.config.database.update(_this14.className, _this14.query, _this14.data, _this14.runOptions).then(function (response) {
response.updatedAt = _this14.updatedAt;
_this14._updateResponseWithData(response, _this14.data);
_this14.response = { response: response };
});
});
} else {
// Set the default ACL and password timestamp for the new _User
if (this.className === '_User') {
var ACL = this.data.ACL;
// default public r/w ACL
if (!ACL) {
ACL = {};
ACL['*'] = { read: true, write: false };
}
// make sure the user is not locked down
ACL[this.data.objectId] = { read: true, write: true };
this.data.ACL = ACL;
// password timestamp to be used when password expiry policy is enforced
if (this.config.passwordPolicy && this.config.passwordPolicy.maxPasswordAge) {
this.data._password_changed_at = Parse._encode(new Date());
}
}
// Run a create
return this.config.database.create(this.className, this.data, this.runOptions).catch(function (error) {
if (_this14.className !== '_User' || error.code !== Parse.Error.DUPLICATE_VALUE) {
throw error;
}
// If this was a failed user creation due to username or email already taken, we need to
// check whether it was username or email and return the appropriate error.
// TODO: See if we can later do this without additional queries by using named indexes.
return _this14.config.database.find(_this14.className, { username: _this14.data.username, objectId: { '$ne': _this14.objectId() } }, { limit: 1 }).then(function (results) {
if (results.length > 0) {
throw new Parse.Error(Parse.Error.USERNAME_TAKEN, 'Account already exists for this username.');
}
return _this14.config.database.find(_this14.className, { email: _this14.data.email, objectId: { '$ne': _this14.objectId() } }, { limit: 1 });
}).then(function (results) {
if (results.length > 0) {
throw new Parse.Error(Parse.Error.EMAIL_TAKEN, 'Account already exists for this email address.');
}
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
});
}).then(function (response) {
response.objectId = _this14.data.objectId;
response.createdAt = _this14.data.createdAt;
if (_this14.responseShouldHaveUsername) {
response.username = _this14.data.username;
}
_this14._updateResponseWithData(response, _this14.data);
_this14.response = {
status: 201,
response: response,
location: _this14.location()
};
});
}
};
// Returns nothing - doesn't wait for the trigger.
RestWrite.prototype.runAfterTrigger = function () {
if (!this.response || !this.response.response) {
return;
}
// Avoid doing any setup for triggers if there is no 'afterSave' trigger for this class.
var hasAfterSaveHook = triggers.triggerExists(this.className, triggers.Types.afterSave, this.config.applicationId);
var hasLiveQuery = this.config.liveQueryController.hasLiveQuery(this.className);
if (!hasAfterSaveHook && !hasLiveQuery) {
return Promise.resolve();
}
var extraData = { className: this.className };
if (this.query && this.query.objectId) {
extraData.objectId = this.query.objectId;
}
// Build the original object, we only do this for a update write.
var originalObject = void 0;
if (this.query && this.query.objectId) {
originalObject = triggers.inflate(extraData, this.originalData);
}
// Build the inflated object, different from beforeSave, originalData is not empty
// since developers can change data in the beforeSave.
var updatedObject = triggers.inflate(extraData, this.originalData);
updatedObject.set(this.sanitizedData());
updatedObject._handleSaveResponse(this.response.response, this.response.status || 200);
// Notifiy LiveQueryServer if possible
this.config.liveQueryController.onAfterSave(updatedObject.className, updatedObject, originalObject);
// Run afterSave trigger
return triggers.maybeRunTrigger(triggers.Types.afterSave, this.auth, updatedObject, originalObject, this.config);
};
// A helper to figure out what location this operation happens at.
RestWrite.prototype.location = function () {
var middle = this.className === '_User' ? '/users/' : '/classes/' + this.className + '/';
return this.config.mount + middle + this.data.objectId;
};
// A helper to get the object id for this operation.
// Because it could be either on the query or on the data
RestWrite.prototype.objectId = function () {
return this.data.objectId || this.query.objectId;
};
// Returns a copy of the data and delete bad keys (_auth_data, _hashed_password...)
RestWrite.prototype.sanitizedData = function () {
var data = Object.keys(this.data).reduce(function (data, key) {
// Regexp comes from Parse.Object.prototype.validate
if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) {
delete data[key];
}
return data;
}, deepcopy(this.data));
return Parse._decode(undefined, data);
};
RestWrite.prototype.cleanUserAuthData = function () {
if (this.response && this.response.response && this.className === '_User') {
var user = this.response.response;
if (user.authData) {
Object.keys(user.authData).forEach(function (provider) {
if (user.authData[provider] === null) {
delete user.authData[provider];
}
});
if (Object.keys(user.authData).length == 0) {
delete user.authData;
}
}
}
};
RestWrite.prototype._updateResponseWithData = function (response, data) {
if (_lodash2.default.isEmpty(this.storage.fieldsChangedByTrigger)) {
return response;
}
var clientSupportsDelete = ClientSDK.supportsForwardDelete(this.clientSDK);
this.storage.fieldsChangedByTrigger.forEach(function (fieldName) {
var dataValue = data[fieldName];
var responseValue = response[fieldName];
response[fieldName] = responseValue || dataValue;
// Strips operations from responses
if (response[fieldName] && response[fieldName].__op) {
delete response[fieldName];
if (clientSupportsDelete && dataValue.__op == 'Delete') {
response[fieldName] = dataValue;
}
}
});
return response;
};
exports.default = RestWrite;
module.exports = RestWrite;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.flatten = flatten;
exports.jobStatusHandler = jobStatusHandler;
exports.pushStatusHandler = pushStatusHandler;
var _cryptoUtils = require('./cryptoUtils');
var _logger = require('./logger');
var PUSH_STATUS_COLLECTION = '_PushStatus';
var JOB_STATUS_COLLECTION = '_JobStatus';
var incrementOp = function incrementOp() {
var object = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var key = arguments[1];
var amount = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
if (!object[key]) {
object[key] = { __op: 'Increment', amount: amount };
} else {
object[key].amount += amount;
}
return object[key];
};
function flatten(array) {
var flattened = [];
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flattened = flattened.concat(flatten(array[i]));
} else {
flattened.push(array[i]);
}
}
return flattened;
}
function statusHandler(className, database) {
var lastPromise = Promise.resolve();
function create(object) {
lastPromise = lastPromise.then(function () {
return database.create(className, object).then(function () {
return Promise.resolve(object);
});
});
return lastPromise;
}
function update(where, object) {
lastPromise = lastPromise.then(function () {
return database.update(className, where, object);
});
return lastPromise;
}
return Object.freeze({
create: create,
update: update
});
}
function jobStatusHandler(config) {
var jobStatus = void 0;
var objectId = (0, _cryptoUtils.newObjectId)();
var database = config.database;
var handler = statusHandler(JOB_STATUS_COLLECTION, database);
var setRunning = function setRunning(jobName, params) {
var now = new Date();
jobStatus = {
objectId: objectId,
jobName: jobName,
params: params,
status: 'running',
source: 'api',
createdAt: now,
// lockdown!
ACL: {}
};
return handler.create(jobStatus);
};
var setMessage = function setMessage(message) {
if (!message || typeof message !== 'string') {
return Promise.resolve();
}
return handler.update({ objectId: objectId }, { message: message });
};
var setSucceeded = function setSucceeded(message) {
return setFinalStatus('succeeded', message);
};
var setFailed = function setFailed(message) {
return setFinalStatus('failed', message);
};
var setFinalStatus = function setFinalStatus(status) {
var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
var finishedAt = new Date();
var update = { status: status, finishedAt: finishedAt };
if (message && typeof message === 'string') {
update.message = message;
}
return handler.update({ objectId: objectId }, update);
};
return Object.freeze({
setRunning: setRunning,
setSucceeded: setSucceeded,
setMessage: setMessage,
setFailed: setFailed
});
}
function pushStatusHandler(config) {
var objectId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : (0, _cryptoUtils.newObjectId)();
var pushStatus = void 0;
var database = config.database;
var handler = statusHandler(PUSH_STATUS_COLLECTION, database);
var setInitial = function setInitial() {
var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var where = arguments[1];
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { source: 'rest' };
var now = new Date();
var data = body.data || {};
var payloadString = JSON.stringify(data);
var pushHash = void 0;
if (typeof data.alert === 'string') {
pushHash = (0, _cryptoUtils.md5Hash)(data.alert);
} else if (_typeof(data.alert) === 'object') {
pushHash = (0, _cryptoUtils.md5Hash)(JSON.stringify(data.alert));
} else {
pushHash = 'd41d8cd98f00b204e9800998ecf8427e';
}
var object = {
objectId: objectId,
createdAt: now,
pushTime: now.toISOString(),
query: JSON.stringify(where),
payload: payloadString,
source: options.source,
title: options.title,
expiry: body.expiration_time,
status: "pending",
numSent: 0,
pushHash: pushHash,
// lockdown!
ACL: {}
};
return handler.create(object).then(function () {
pushStatus = {
objectId: objectId
};
return Promise.resolve(pushStatus);
});
};
var setRunning = function setRunning(count) {
_logger.logger.verbose('_PushStatus ' + objectId + ': sending push to %d installations', count);
return handler.update({ status: "pending", objectId: objectId }, { status: "running", updatedAt: new Date(), count: count });
};
var trackSent = function trackSent(results) {
var _this = this;
var update = {
updatedAt: new Date(),
numSent: 0,
numFailed: 0
};
if (Array.isArray(results)) {
results = flatten(results);
results.reduce(function (memo, result) {
// Cannot handle that
if (!result || !result.device || !result.device.deviceType) {
return memo;
}
var deviceType = result.device.deviceType;
var key = result.transmitted ? 'sentPerType.' + deviceType : 'failedPerType.' + deviceType;
memo[key] = incrementOp(memo, key);
if (result.transmitted) {
memo.numSent++;
} else {
memo.numFailed++;
}
return memo;
}, update);
incrementOp(update, 'count', -results.length);
}
_logger.logger.verbose('_PushStatus ' + objectId + ': sent push! %d success, %d failures', update.numSent, update.numFailed);
['numSent', 'numFailed'].forEach(function (key) {
if (update[key] > 0) {
update[key] = {
__op: 'Increment',
amount: update[key]
};
} else {
delete update[key];
}
});
return handler.update({ objectId: objectId }, update).then(function (res) {
if (res && res.count === 0) {
return _this.complete();
}
});
};
var complete = function complete() {
return handler.update({ objectId: objectId }, {
status: 'succeeded',
count: { __op: 'Delete' },
updatedAt: new Date()
});
};
var fail = function fail(err) {
var update = {
errorMessage: JSON.stringify(err),
status: 'failed',
updatedAt: new Date()
};
_logger.logger.warn('_PushStatus ' + objectId + ': error while sending push', err);
return handler.update({ objectId: objectId }, update);
};
return Object.freeze({
objectId: objectId,
setInitial: setInitial,
setRunning: setRunning,
trackSent: trackSent,
complete: complete,
fail: fail
});
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.destroyAllDataPermanently = destroyAllDataPermanently;
var _cache = require('./cache');
var _cache2 = _interopRequireDefault(_cache);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//Used by tests
function destroyAllDataPermanently() {
if (!process.env.TESTING) {
throw 'Only supported in test environment';
}
return Promise.all(Object.keys(_cache2.default.cache).map(function (appId) {
var app = _cache2.default.get(appId);
if (app.databaseController) {
return app.databaseController.deleteEverything();
} else {
return Promise.resolve();
}
}));
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 1 1 1 1 1 1 1 1 1 | 'use strict';
var Parse = require('parse/node').Parse;
var url = require('url');
var path = require('path');
// These methods handle batch requests.
var batchPath = '/batch';
// Mounts a batch-handler onto a PromiseRouter.
function mountOnto(router) {
router.route('POST', batchPath, function (req) {
return handleBatch(router, req);
});
}
function parseURL(URL) {
if (typeof URL === 'string') {
return url.parse(URL);
}
return undefined;
}
function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) {
serverURL = serverURL ? parseURL(serverURL) : undefined;
publicServerURL = publicServerURL ? parseURL(publicServerURL) : undefined;
var apiPrefixLength = originalUrl.length - batchPath.length;
var apiPrefix = originalUrl.slice(0, apiPrefixLength);
var makeRoutablePath = function makeRoutablePath(requestPath) {
// The routablePath is the path minus the api prefix
if (requestPath.slice(0, apiPrefix.length) != apiPrefix) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'cannot route batch path ' + requestPath);
}
return path.posix.join('/', requestPath.slice(apiPrefix.length));
};
if (serverURL && publicServerURL && serverURL.path != publicServerURL.path) {
var localPath = serverURL.path;
var publicPath = publicServerURL.path;
// Override the api prefix
apiPrefix = localPath;
return function (requestPath) {
// Build the new path by removing the public path
// and joining with the local path
var newPath = path.posix.join('/', localPath, '/', requestPath.slice(publicPath.length));
// Use the method for local routing
return makeRoutablePath(newPath);
};
}
return makeRoutablePath;
}
// Returns a promise for a {response} object.
// TODO: pass along auth correctly
function handleBatch(router, req) {
if (!Array.isArray(req.body.requests)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'requests must be an array');
}
// The batch paths are all from the root of our domain.
// That means they include the API prefix, that the API is mounted
// to. However, our promise router does not route the api prefix. So
// we need to figure out the API prefix, so that we can strip it
// from all the subrequests.
if (!req.originalUrl.endsWith(batchPath)) {
throw 'internal routing problem - expected url to end with batch';
}
var makeRoutablePath = makeBatchRoutingPathFunction(req.originalUrl, req.config.serverURL, req.config.publicServerURL);
var promises = req.body.requests.map(function (restRequest) {
var routablePath = makeRoutablePath(restRequest.path);
// Construct a request that we can send to a handler
var request = {
body: restRequest.body,
config: req.config,
auth: req.auth,
info: req.info
};
return router.tryRouteRequest(restRequest.method, routablePath, request).then(function (response) {
return { success: response.response };
}, function (error) {
return { error: { code: error.code, error: error.message } };
});
});
return Promise.all(promises).then(function (results) {
return { response: results };
});
}
module.exports = {
mountOnto: mountOnto,
makeBatchRoutingPathFunction: makeBatchRoutingPathFunction
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AppCache = undefined;
var _InMemoryCache = require('./Adapters/Cache/InMemoryCache');
var AppCache = exports.AppCache = new _InMemoryCache.InMemoryCache({ ttl: NaN });
exports.default = AppCache;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.randomHexString = randomHexString;
exports.randomString = randomString;
exports.newObjectId = newObjectId;
exports.newToken = newToken;
exports.md5Hash = md5Hash;
var _crypto = require('crypto');
// Returns a new random hex string of the given even size.
function randomHexString(size) {
if (size === 0) {
throw new Error('Zero-length randomHexString is useless.');
}
if (size % 2 !== 0) {
throw new Error('randomHexString size must be divisible by 2.');
}
return (0, _crypto.randomBytes)(size / 2).toString('hex');
}
// Returns a new random alphanumeric string of the given size.
//
// Note: to simplify implementation, the result has slight modulo bias,
// because chars length of 62 doesn't divide the number of all bytes
// (256) evenly. Such bias is acceptable for most cases when the output
// length is long enough and doesn't need to be uniform.
function randomString(size) {
if (size === 0) {
throw new Error('Zero-length randomString is useless.');
}
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789';
var objectId = '';
var bytes = (0, _crypto.randomBytes)(size);
for (var i = 0; i < bytes.length; ++i) {
objectId += chars[bytes.readUInt8(i) % chars.length];
}
return objectId;
}
// Returns a new random alphanumeric string suitable for object ID.
function newObjectId() {
//TODO: increase length to better protect against collisions.
return randomString(10);
}
// Returns a new random hex string suitable for secure tokens.
function newToken() {
return randomHexString(32);
}
function md5Hash(string) {
return (0, _crypto.createHash)('md5').update(string).digest('hex');
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _parsers = require('./cli/utils/parsers');
var logsFolder = function () {
var folder = './logs/';
Eif (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
folder = './test_logs/';
}
Iif (process.env.PARSE_SERVER_LOGS_FOLDER) {
folder = (0, _parsers.nullParser)(process.env.PARSE_SERVER_LOGS_FOLDER);
}
return folder;
}();
var _ref = function () {
var verbose = process.env.VERBOSE ? true : false;
return { verbose: verbose, level: verbose ? 'verbose' : undefined };
}(),
verbose = _ref.verbose,
level = _ref.level;
exports.default = {
DefaultMongoURI: 'mongodb://localhost:27017/parse',
jsonLogs: process.env.JSON_LOGS || false,
logsFolder: logsFolder,
verbose: verbose,
level: level,
silent: false,
enableAnonymousUsers: true,
allowClientClassCreation: true,
maxUploadSize: '20mb',
verifyUserEmails: false,
preventLoginWithUnverifiedEmail: false,
sessionLength: 31536000,
expireInactiveSessions: true,
revokeSessionOnPasswordReset: true,
schemaCacheTTL: 5000, // in ms
userSensitiveFields: ['email']
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useExternal = useExternal;
function useExternal(name, moduleName) {
return function () {
throw name + " is not provided by parse-server anymore; please install " + moduleName;
};
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 6 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParseServer = exports.PushWorker = exports.TestUtils = exports.RedisCacheAdapter = exports.NullCacheAdapter = exports.InMemoryCacheAdapter = exports.FileSystemAdapter = exports.GCSAdapter = exports.S3Adapter = undefined;
var _ParseServer2 = require('./ParseServer');
var _ParseServer3 = _interopRequireDefault(_ParseServer2);
var _parseServerS3Adapter = require('parse-server-s3-adapter');
var _parseServerS3Adapter2 = _interopRequireDefault(_parseServerS3Adapter);
var _parseServerFsAdapter = require('parse-server-fs-adapter');
var _parseServerFsAdapter2 = _interopRequireDefault(_parseServerFsAdapter);
var _InMemoryCacheAdapter = require('./Adapters/Cache/InMemoryCacheAdapter');
var _InMemoryCacheAdapter2 = _interopRequireDefault(_InMemoryCacheAdapter);
var _NullCacheAdapter = require('./Adapters/Cache/NullCacheAdapter');
var _NullCacheAdapter2 = _interopRequireDefault(_NullCacheAdapter);
var _RedisCacheAdapter = require('./Adapters/Cache/RedisCacheAdapter');
var _RedisCacheAdapter2 = _interopRequireDefault(_RedisCacheAdapter);
var _TestUtils = require('./TestUtils');
var TestUtils = _interopRequireWildcard(_TestUtils);
var _deprecated = require('./deprecated');
var _logger = require('./logger');
var _PushWorker = require('./Push/PushWorker');
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Factory function
var _ParseServer = function _ParseServer(options) {
var server = new _ParseServer3.default(options);
return server.app;
};
// Mount the create liveQueryServer
_ParseServer.createLiveQueryServer = _ParseServer3.default.createLiveQueryServer;
var GCSAdapter = (0, _deprecated.useExternal)('GCSAdapter', 'parse-server-gcs-adapter');
Object.defineProperty(module.exports, 'logger', {
get: _logger.getLogger
});
exports.default = _ParseServer3.default;
exports.S3Adapter = _parseServerS3Adapter2.default;
exports.GCSAdapter = GCSAdapter;
exports.FileSystemAdapter = _parseServerFsAdapter2.default;
exports.InMemoryCacheAdapter = _InMemoryCacheAdapter2.default;
exports.NullCacheAdapter = _NullCacheAdapter2.default;
exports.RedisCacheAdapter = _RedisCacheAdapter2.default;
exports.TestUtils = TestUtils;
exports.PushWorker = _PushWorker.PushWorker;
exports.ParseServer = _ParseServer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.setLogger = setLogger;
exports.getLogger = getLogger;
var _defaults = require('./defaults');
var _defaults2 = _interopRequireDefault(_defaults);
var _WinstonLoggerAdapter = require('./Adapters/Logger/WinstonLoggerAdapter');
var _LoggerController = require('./Controllers/LoggerController');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function defaultLogger() {
var adapter = new _WinstonLoggerAdapter.WinstonLoggerAdapter({
logsFolder: _defaults2.default.logsFolder,
jsonLogs: _defaults2.default.jsonLogs,
verbose: _defaults2.default.verbose,
silent: _defaults2.default.silent });
return new _LoggerController.LoggerController(adapter);
}
var logger = defaultLogger();
function setLogger(aLogger) {
logger = aLogger;
}
function getLogger() {
return logger;
}
// for: `import logger from './logger'`
Object.defineProperty(module.exports, 'default', {
get: getLogger
});
// for: `import { logger } from './logger'`
Object.defineProperty(module.exports, 'logger', {
get: getLogger
});
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 6 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.handleParseHeaders = handleParseHeaders;
exports.allowCrossDomain = allowCrossDomain;
exports.allowMethodOverride = allowMethodOverride;
exports.handleParseErrors = handleParseErrors;
exports.enforceMasterKeyAccess = enforceMasterKeyAccess;
exports.promiseEnforceMasterKeyAccess = promiseEnforceMasterKeyAccess;
var _cache = require('./cache');
var _cache2 = _interopRequireDefault(_cache);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _Auth = require('./Auth');
var _Auth2 = _interopRequireDefault(_Auth);
var _Config = require('./Config');
var _Config2 = _interopRequireDefault(_Config);
var _ClientSDK = require('./ClientSDK');
var _ClientSDK2 = _interopRequireDefault(_ClientSDK);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Checks that the request is authorized for this app and checks user
// auth too.
// The bodyparser should run before this middleware.
// Adds info to the request:
// req.config - the Config for this app
// req.auth - the Auth for this request
function handleParseHeaders(req, res, next) {
var mountPathLength = req.originalUrl.length - req.url.length;
var mountPath = req.originalUrl.slice(0, mountPathLength);
var mount = req.protocol + '://' + req.get('host') + mountPath;
var info = {
appId: req.get('X-Parse-Application-Id'),
sessionToken: req.get('X-Parse-Session-Token'),
masterKey: req.get('X-Parse-Master-Key'),
installationId: req.get('X-Parse-Installation-Id'),
clientKey: req.get('X-Parse-Client-Key'),
javascriptKey: req.get('X-Parse-Javascript-Key'),
dotNetKey: req.get('X-Parse-Windows-Key'),
restAPIKey: req.get('X-Parse-REST-API-Key'),
clientVersion: req.get('X-Parse-Client-Version')
};
var basicAuth = httpAuth(req);
if (basicAuth) {
var basicAuthAppId = basicAuth.appId;
if (_cache2.default.get(basicAuthAppId)) {
info.appId = basicAuthAppId;
info.masterKey = basicAuth.masterKey || info.masterKey;
info.javascriptKey = basicAuth.javascriptKey || info.javascriptKey;
}
}
if (req.body) {
// Unity SDK sends a _noBody key which needs to be removed.
// Unclear at this point if action needs to be taken.
delete req.body._noBody;
}
var fileViaJSON = false;
if (!info.appId || !_cache2.default.get(info.appId)) {
// See if we can find the app id on the body.
if (req.body instanceof Buffer) {
// The only chance to find the app id is if this is a file
// upload that actually is a JSON body. So try to parse it.
req.body = JSON.parse(req.body);
fileViaJSON = true;
}
if (req.body) {
delete req.body._RevocableSession;
}
if (req.body && req.body._ApplicationId && _cache2.default.get(req.body._ApplicationId) && (!info.masterKey || _cache2.default.get(req.body._ApplicationId).masterKey === info.masterKey)) {
info.appId = req.body._ApplicationId;
info.javascriptKey = req.body._JavaScriptKey || '';
delete req.body._ApplicationId;
delete req.body._JavaScriptKey;
// TODO: test that the REST API formats generated by the other
// SDKs are handled ok
if (req.body._ClientVersion) {
info.clientVersion = req.body._ClientVersion;
delete req.body._ClientVersion;
}
if (req.body._InstallationId) {
info.installationId = req.body._InstallationId;
delete req.body._InstallationId;
}
if (req.body._SessionToken) {
info.sessionToken = req.body._SessionToken;
delete req.body._SessionToken;
}
if (req.body._MasterKey) {
info.masterKey = req.body._MasterKey;
delete req.body._MasterKey;
}
if (req.body._ContentType) {
req.headers['content-type'] = req.body._ContentType;
delete req.body._ContentType;
}
} else {
return invalidRequest(req, res);
}
}
if (info.clientVersion) {
info.clientSDK = _ClientSDK2.default.fromString(info.clientVersion);
}
if (fileViaJSON) {
// We need to repopulate req.body with a buffer
var base64 = req.body.base64;
req.body = new Buffer(base64, 'base64');
}
info.app = _cache2.default.get(info.appId);
req.config = new _Config2.default(info.appId, mount);
req.info = info;
var isMaster = info.masterKey === req.config.masterKey;
if (isMaster) {
req.auth = new _Auth2.default.Auth({ config: req.config, installationId: info.installationId, isMaster: true });
next();
return;
}
// Client keys are not required in parse-server, but if any have been configured in the server, validate them
// to preserve original behavior.
var keys = ["clientKey", "javascriptKey", "dotNetKey", "restAPIKey"];
var oneKeyConfigured = keys.some(function (key) {
return req.config[key] !== undefined;
});
var oneKeyMatches = keys.some(function (key) {
return req.config[key] !== undefined && info[key] === req.config[key];
});
if (oneKeyConfigured && !oneKeyMatches) {
return invalidRequest(req, res);
}
if (req.url == "/login") {
delete info.sessionToken;
}
if (!info.sessionToken) {
req.auth = new _Auth2.default.Auth({ config: req.config, installationId: info.installationId, isMaster: false });
next();
return;
}
return Promise.resolve().then(function () {
// handle the upgradeToRevocableSession path on it's own
if (info.sessionToken && req.url === '/upgradeToRevocableSession' && info.sessionToken.indexOf('r:') != 0) {
return _Auth2.default.getAuthForLegacySessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken });
} else {
return _Auth2.default.getAuthForSessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken });
}
}).then(function (auth) {
if (auth) {
req.auth = auth;
next();
}
}).catch(function (error) {
if (error instanceof _node2.default.Error) {
next(error);
return;
} else {
// TODO: Determine the correct error scenario.
_logger2.default.error('error getting auth for sessionToken', error);
throw new _node2.default.Error(_node2.default.Error.UNKNOWN_ERROR, error);
}
});
}
function httpAuth(req) {
if (!(req.req || req).headers.authorization) return;
var header = (req.req || req).headers.authorization;
var appId, masterKey, javascriptKey;
// parse header
var authPrefix = 'basic ';
var match = header.toLowerCase().indexOf(authPrefix);
if (match == 0) {
var encodedAuth = header.substring(authPrefix.length, header.length);
var credentials = decodeBase64(encodedAuth).split(':');
if (credentials.length == 2) {
appId = credentials[0];
var key = credentials[1];
var jsKeyPrefix = 'javascript-key=';
var matchKey = key.indexOf(jsKeyPrefix);
if (matchKey == 0) {
javascriptKey = key.substring(jsKeyPrefix.length, key.length);
} else {
masterKey = key;
}
}
}
return { appId: appId, masterKey: masterKey, javascriptKey: javascriptKey };
}
function decodeBase64(str) {
return new Buffer(str, 'base64').toString();
}
function allowCrossDomain(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.sendStatus(200);
} else {
next();
}
}
function allowMethodOverride(req, res, next) {
if (req.method === 'POST' && req.body._method) {
req.originalMethod = req.method;
req.method = req.body._method;
delete req.body._method;
}
next();
}
function handleParseErrors(err, req, res, next) {
if (err instanceof _node2.default.Error) {
var httpStatus = void 0;
// TODO: fill out this mapping
switch (err.code) {
case _node2.default.Error.INTERNAL_SERVER_ERROR:
httpStatus = 500;
break;
case _node2.default.Error.OBJECT_NOT_FOUND:
httpStatus = 404;
break;
default:
httpStatus = 400;
}
res.status(httpStatus);
res.json({ code: err.code, error: err.message });
_logger2.default.error(err.message, err);
} else if (err.status && err.message) {
res.status(err.status);
res.json({ error: err.message });
next(err);
} else {
_logger2.default.error('Uncaught internal server error.', err, err.stack);
res.status(500);
res.json({
code: _node2.default.Error.INTERNAL_SERVER_ERROR,
message: 'Internal server error.'
});
next(err);
}
}
function enforceMasterKeyAccess(req, res, next) {
if (!req.auth.isMaster) {
res.status(403);
res.end('{"error":"unauthorized: master key is required"}');
return;
}
next();
}
function promiseEnforceMasterKeyAccess(request) {
if (!request.auth.isMaster) {
var error = new Error();
error.status = 403;
error.message = "unauthorized: master key is required";
throw error;
}
return Promise.resolve();
}
function invalidRequest(req, res) {
res.status(403);
res.end('{"error":"unauthorized"}');
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 | 'use strict';
// Tools for encrypting and decrypting passwords.
// Basically promise-friendly wrappers for bcrypt.
var bcrypt = require('bcryptjs');
try {
bcrypt = require('bcrypt');
} catch (e) {} /* */
// Returns a promise for a hashed password string.
function hash(password) {
return new Promise(function (fulfill, reject) {
bcrypt.hash(password, 10, function (err, hashedPassword) {
if (err) {
reject(err);
} else {
fulfill(hashedPassword);
}
});
});
}
// Returns a promise for whether this password compares to equal this
// hashed password.
function compare(password, hashedPassword) {
return new Promise(function (fulfill, reject) {
// Cannot bcrypt compare when one is undefined
if (!password || !hashedPassword) {
return fulfill(false);
}
bcrypt.compare(password, hashedPassword, function (err, success) {
if (err) {
reject(err);
} else {
fulfill(success);
}
});
});
}
module.exports = {
hash: hash,
compare: compare
};
|
| 1 2 3 4 5 6 7 8 9 10 | 1 1 2 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (errorMessage) {
throw errorMessage;
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var _Auth = require('./Auth');
var _Auth2 = _interopRequireDefault(_Auth);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// This file contains helpers for running operations in REST format.
// The goal is that handlers that explicitly handle an express route
// should just be shallow wrappers around things in this file, but
// these functions should not explicitly depend on the request
// object.
// This means that one of these handlers can support multiple
// routes. That's useful for the routes that do really similar
// things.
var Parse = require('parse/node').Parse;
var RestQuery = require('./RestQuery');
var RestWrite = require('./RestWrite');
var triggers = require('./triggers');
function checkTriggers(className, config, types) {
return types.some(function (triggerType) {
return triggers.getTrigger(className, triggers.Types[triggerType], config.applicationId);
});
}
function checkLiveQuery(className, config) {
return config.liveQueryController && config.liveQueryController.hasLiveQuery(className);
}
// Returns a promise for an object with optional keys 'results' and 'count'.
function find(config, auth, className, restWhere, restOptions, clientSDK) {
enforceRoleSecurity('find', className, auth);
return triggers.maybeRunQueryTrigger(triggers.Types.beforeFind, className, restWhere, restOptions, config, auth).then(function (result) {
restWhere = result.restWhere || restWhere;
restOptions = result.restOptions || restOptions;
var query = new RestQuery(config, auth, className, restWhere, restOptions, clientSDK);
return query.execute();
});
}
// get is just like find but only queries an objectId.
var get = function get(config, auth, className, objectId, restOptions, clientSDK) {
enforceRoleSecurity('get', className, auth);
var query = new RestQuery(config, auth, className, { objectId: objectId }, restOptions, clientSDK);
return query.execute();
};
// Returns a promise that doesn't resolve to any useful value.
function del(config, auth, className, objectId) {
if (typeof objectId !== 'string') {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad objectId');
}
if (className === '_User' && !auth.couldUpdateUserId(objectId)) {
throw new Parse.Error(Parse.Error.SESSION_MISSING, 'insufficient auth to delete user');
}
enforceRoleSecurity('delete', className, auth);
var inflatedObject;
return Promise.resolve().then(function () {
var hasTriggers = checkTriggers(className, config, ['beforeDelete', 'afterDelete']);
var hasLiveQuery = checkLiveQuery(className, config);
if (hasTriggers || hasLiveQuery || className == '_Session') {
return find(config, _Auth2.default.master(config), className, { objectId: objectId }).then(function (response) {
if (response && response.results && response.results.length) {
response.results[0].className = className;
var cacheAdapter = config.cacheController;
cacheAdapter.user.del(response.results[0].sessionToken);
inflatedObject = Parse.Object.fromJSON(response.results[0]);
// Notify LiveQuery server if possible
config.liveQueryController.onAfterDelete(inflatedObject.className, inflatedObject);
return triggers.maybeRunTrigger(triggers.Types.beforeDelete, auth, inflatedObject, null, config);
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found for delete.');
});
}
return Promise.resolve({});
}).then(function () {
if (!auth.isMaster) {
return auth.getUserRoles();
} else {
return;
}
}).then(function () {
var options = {};
if (!auth.isMaster) {
options.acl = ['*'];
if (auth.user) {
options.acl.push(auth.user.id);
options.acl = options.acl.concat(auth.userRoles);
}
}
return config.database.destroy(className, {
objectId: objectId
}, options);
}).then(function () {
return triggers.maybeRunTrigger(triggers.Types.afterDelete, auth, inflatedObject, null, config);
});
}
// Returns a promise for a {response, status, location} object.
function create(config, auth, className, restObject, clientSDK) {
enforceRoleSecurity('create', className, auth);
var write = new RestWrite(config, auth, className, null, restObject, null, clientSDK);
return write.execute();
}
// Returns a promise that contains the fields of the update that the
// REST API is supposed to return.
// Usually, this is just updatedAt.
function update(config, auth, className, objectId, restObject, clientSDK) {
enforceRoleSecurity('update', className, auth);
return Promise.resolve().then(function () {
var hasTriggers = checkTriggers(className, config, ['beforeSave', 'afterSave']);
var hasLiveQuery = checkLiveQuery(className, config);
if (hasTriggers || hasLiveQuery) {
return find(config, _Auth2.default.master(config), className, { objectId: objectId });
}
return Promise.resolve({});
}).then(function (response) {
var originalRestObject;
if (response && response.results && response.results.length) {
originalRestObject = response.results[0];
}
var write = new RestWrite(config, auth, className, { objectId: objectId }, restObject, originalRestObject, clientSDK);
return write.execute();
});
}
// Disallowing access to the _Role collection except by master key
function enforceRoleSecurity(method, className, auth) {
if (className === '_Installation' && !auth.isMaster) {
if (method === 'delete' || method === 'find') {
var error = 'Clients aren\'t allowed to perform the ' + method + ' operation on the installation collection.';
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error);
}
}
}
module.exports = {
create: create,
del: del,
find: find,
get: get,
update: update
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Types = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; // triggers.js
exports.addFunction = addFunction;
exports.addJob = addJob;
exports.addTrigger = addTrigger;
exports.removeFunction = removeFunction;
exports.removeJob = removeJob;
exports.removeTrigger = removeTrigger;
exports._unregister = _unregister;
exports._unregisterAll = _unregisterAll;
exports.getTrigger = getTrigger;
exports.triggerExists = triggerExists;
exports.getFunction = getFunction;
exports.getJob = getJob;
exports.getJobs = getJobs;
exports.getValidator = getValidator;
exports.getRequestObject = getRequestObject;
exports.getRequestQueryObject = getRequestQueryObject;
exports.getResponseObject = getResponseObject;
exports.maybeRunAfterFindTrigger = maybeRunAfterFindTrigger;
exports.maybeRunQueryTrigger = maybeRunQueryTrigger;
exports.maybeRunTrigger = maybeRunTrigger;
exports.inflate = inflate;
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _logger = require('./logger');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Types = exports.Types = {
beforeSave: 'beforeSave',
afterSave: 'afterSave',
beforeDelete: 'beforeDelete',
afterDelete: 'afterDelete',
beforeFind: 'beforeFind',
afterFind: 'afterFind'
};
var baseStore = function baseStore() {
var Validators = {};
var Functions = {};
var Jobs = {};
var Triggers = Object.keys(Types).reduce(function (base, key) {
base[key] = {};
return base;
}, {});
return Object.freeze({
Functions: Functions,
Jobs: Jobs,
Validators: Validators,
Triggers: Triggers
});
};
var _triggerStore = {};
function addFunction(functionName, handler, validationHandler, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
_triggerStore[applicationId] = _triggerStore[applicationId] || baseStore();
_triggerStore[applicationId].Functions[functionName] = handler;
_triggerStore[applicationId].Validators[functionName] = validationHandler;
}
function addJob(jobName, handler, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
_triggerStore[applicationId] = _triggerStore[applicationId] || baseStore();
_triggerStore[applicationId].Jobs[jobName] = handler;
}
function addTrigger(type, className, handler, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
_triggerStore[applicationId] = _triggerStore[applicationId] || baseStore();
_triggerStore[applicationId].Triggers[type][className] = handler;
}
function removeFunction(functionName, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
delete _triggerStore[applicationId].Functions[functionName];
}
function removeJob(jobName, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
delete _triggerStore[applicationId].Jobs[jobName];
}
function removeTrigger(type, className, applicationId) {
applicationId = applicationId || _node2.default.applicationId;
delete _triggerStore[applicationId].Triggers[type][className];
}
function _unregister(appId, category, className, type) {
if (type) {
removeTrigger(className, type, appId);
delete _triggerStore[appId][category][className][type];
} else {
delete _triggerStore[appId][category][className];
}
}
function _unregisterAll() {
Object.keys(_triggerStore).forEach(function (appId) {
return delete _triggerStore[appId];
});
}
function getTrigger(className, triggerType, applicationId) {
if (!applicationId) {
throw "Missing ApplicationID";
}
var manager = _triggerStore[applicationId];
if (manager && manager.Triggers && manager.Triggers[triggerType] && manager.Triggers[triggerType][className]) {
return manager.Triggers[triggerType][className];
}
return undefined;
}
function triggerExists(className, type, applicationId) {
return getTrigger(className, type, applicationId) != undefined;
}
function getFunction(functionName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Functions) {
return manager.Functions[functionName];
}
return undefined;
}
function getJob(jobName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Jobs) {
return manager.Jobs[jobName];
}
return undefined;
}
function getJobs(applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Jobs) {
return manager.Jobs;
}
return undefined;
}
function getValidator(functionName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Validators) {
return manager.Validators[functionName];
}
return undefined;
}
function getRequestObject(triggerType, auth, parseObject, originalParseObject, config) {
var request = {
triggerName: triggerType,
object: parseObject,
master: false,
log: config.loggerController
};
if (originalParseObject) {
request.original = originalParseObject;
}
if (!auth) {
return request;
}
if (auth.isMaster) {
request['master'] = true;
}
if (auth.user) {
request['user'] = auth.user;
}
if (auth.installationId) {
request['installationId'] = auth.installationId;
}
return request;
}
function getRequestQueryObject(triggerType, auth, query, config) {
var request = {
triggerName: triggerType,
query: query,
master: false,
log: config.loggerController
};
if (!auth) {
return request;
}
if (auth.isMaster) {
request['master'] = true;
}
if (auth.user) {
request['user'] = auth.user;
}
if (auth.installationId) {
request['installationId'] = auth.installationId;
}
return request;
}
// Creates the response object, and uses the request object to pass data
// The API will call this with REST API formatted objects, this will
// transform them to Parse.Object instances expected by Cloud Code.
// Any changes made to the object in a beforeSave will be included.
function getResponseObject(request, resolve, reject) {
return {
success: function success(response) {
if (request.triggerName === Types.afterFind) {
if (!response) {
response = request.objects;
}
response = response.map(function (object) {
return object.toJSON();
});
return resolve(response);
}
// Use the JSON response
if (response && !request.object.equals(response) && request.triggerName === Types.beforeSave) {
return resolve(response);
}
response = {};
if (request.triggerName === Types.beforeSave) {
response['object'] = request.object._getSaveJSON();
}
return resolve(response);
},
error: function error(code, message) {
if (!message) {
message = code;
code = _node2.default.Error.SCRIPT_FAILED;
}
var scriptError = new _node2.default.Error(code, message);
return reject(scriptError);
}
};
}
function userIdForLog(auth) {
return auth && auth.user ? auth.user.id : undefined;
}
function logTriggerAfterHook(triggerType, className, input, auth) {
var cleanInput = _logger.logger.truncateLogMessage(JSON.stringify(input));
_logger.logger.info(triggerType + ' triggered for ' + className + ' for user ' + userIdForLog(auth) + ':\n Input: ' + cleanInput, {
className: className,
triggerType: triggerType,
user: userIdForLog(auth)
});
}
function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth) {
var cleanInput = _logger.logger.truncateLogMessage(JSON.stringify(input));
var cleanResult = _logger.logger.truncateLogMessage(JSON.stringify(result));
_logger.logger.info(triggerType + ' triggered for ' + className + ' for user ' + userIdForLog(auth) + ':\n Input: ' + cleanInput + '\n Result: ' + cleanResult, {
className: className,
triggerType: triggerType,
user: userIdForLog(auth)
});
}
function logTriggerErrorBeforeHook(triggerType, className, input, auth, error) {
var cleanInput = _logger.logger.truncateLogMessage(JSON.stringify(input));
_logger.logger.error(triggerType + ' failed for ' + className + ' for user ' + userIdForLog(auth) + ':\n Input: ' + cleanInput + '\n Error: ' + JSON.stringify(error), {
className: className,
triggerType: triggerType,
error: error,
user: userIdForLog(auth)
});
}
function maybeRunAfterFindTrigger(triggerType, auth, className, objects, config) {
return new Promise(function (resolve, reject) {
var trigger = getTrigger(className, triggerType, config.applicationId);
if (!trigger) {
return resolve();
}
var request = getRequestObject(triggerType, auth, null, null, config);
var response = getResponseObject(request, function (object) {
resolve(object);
}, function (error) {
reject(error);
});
logTriggerSuccessBeforeHook(triggerType, className, 'AfterFind', JSON.stringify(objects), auth);
request.objects = objects.map(function (object) {
//setting the class name to transform into parse object
object.className = className;
return _node2.default.Object.fromJSON(object);
});
var triggerPromise = trigger(request, response);
if (triggerPromise && typeof triggerPromise.then === "function") {
return triggerPromise.then(function (promiseResults) {
if (promiseResults) {
resolve(promiseResults);
} else {
return reject(new _node2.default.Error(_node2.default.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
}
});
}
}).then(function (results) {
logTriggerAfterHook(triggerType, className, JSON.stringify(results), auth);
return results;
});
}
function maybeRunQueryTrigger(triggerType, className, restWhere, restOptions, config, auth) {
var trigger = getTrigger(className, triggerType, config.applicationId);
if (!trigger) {
return Promise.resolve({
restWhere: restWhere,
restOptions: restOptions
});
}
var parseQuery = new _node2.default.Query(className);
if (restWhere) {
parseQuery._where = restWhere;
}
if (restOptions) {
if (restOptions.include && restOptions.include.length > 0) {
parseQuery._include = restOptions.include.split(',');
}
if (restOptions.skip) {
parseQuery._skip = restOptions.skip;
}
if (restOptions.limit) {
parseQuery._limit = restOptions.limit;
}
}
var requestObject = getRequestQueryObject(triggerType, auth, parseQuery, config);
return Promise.resolve().then(function () {
return trigger(requestObject);
}).then(function (result) {
var queryResult = parseQuery;
if (result && result instanceof _node2.default.Query) {
queryResult = result;
}
var jsonQuery = queryResult.toJSON();
if (jsonQuery.where) {
restWhere = jsonQuery.where;
}
if (jsonQuery.limit) {
restOptions = restOptions || {};
restOptions.limit = jsonQuery.limit;
}
if (jsonQuery.skip) {
restOptions = restOptions || {};
restOptions.skip = jsonQuery.skip;
}
if (jsonQuery.include) {
restOptions = restOptions || {};
restOptions.include = jsonQuery.include;
}
if (jsonQuery.keys) {
restOptions = restOptions || {};
restOptions.keys = jsonQuery.keys;
}
return {
restWhere: restWhere,
restOptions: restOptions
};
}, function (err) {
if (typeof err === 'string') {
throw new _node2.default.Error(1, err);
} else {
throw err;
}
});
}
// To be used as part of the promise chain when saving/deleting an object
// Will resolve successfully if no trigger is configured
// Resolves to an object, empty or containing an object key. A beforeSave
// trigger will set the object key to the rest format object to save.
// originalParseObject is optional, we only need that for before/afterSave functions
function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, config) {
if (!parseObject) {
return Promise.resolve({});
}
return new Promise(function (resolve, reject) {
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
if (!trigger) return resolve();
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
var response = getResponseObject(request, function (object) {
logTriggerSuccessBeforeHook(triggerType, parseObject.className, parseObject.toJSON(), object, auth);
resolve(object);
}, function (error) {
logTriggerErrorBeforeHook(triggerType, parseObject.className, parseObject.toJSON(), auth, error);
reject(error);
});
// Force the current Parse app before the trigger
_node2.default.applicationId = config.applicationId;
_node2.default.javascriptKey = config.javascriptKey || '';
_node2.default.masterKey = config.masterKey;
// AfterSave and afterDelete triggers can return a promise, which if they
// do, needs to be resolved before this promise is resolved,
// so trigger execution is synced with RestWrite.execute() call.
// If triggers do not return a promise, they can run async code parallel
// to the RestWrite.execute() call.
var triggerPromise = trigger(request, response);
if (triggerType === Types.afterSave || triggerType === Types.afterDelete) {
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
if (triggerPromise && typeof triggerPromise.then === "function") {
return triggerPromise.then(resolve, resolve);
} else {
return resolve();
}
}
});
}
// Converts a REST-format object to a Parse.Object
// data is either className or an object
function inflate(data, restObject) {
var copy = (typeof data === 'undefined' ? 'undefined' : _typeof(data)) == 'object' ? data : { className: data };
for (var key in restObject) {
copy[key] = restObject[key];
}
return _node2.default.Object.fromJSON(copy);
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AdapterLoader.js | 48.15% | (13 / 27) | 44.44% | (8 / 18) | 100% | (1 / 1) | 48.15% | (13 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 2 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.loadAdapter = loadAdapter;
function loadAdapter(adapter, defaultAdapter, options) {
if (!adapter) {
Iif (!defaultAdapter) {
return options;
}
// Load from the default adapter when no adapter is set
return loadAdapter(defaultAdapter, undefined, options);
} else Iif (typeof adapter === "function") {
try {
return adapter(options);
} catch (e) {
if (e.name === 'TypeError') {
var Adapter = adapter;
return new Adapter(options);
} else {
throw e;
}
}
} else Iif (typeof adapter === "string") {
/* eslint-disable */
adapter = require(adapter);
// If it's define as a module, get the default
if (adapter.default) {
adapter = adapter.default;
}
return loadAdapter(adapter, undefined, options);
} else Iif (adapter.module) {
return loadAdapter(adapter.module, undefined, adapter.options);
} else Iif (adapter.class) {
return loadAdapter(adapter.class, undefined, adapter.options);
} else Iif (adapter.adapter) {
return loadAdapter(adapter.adapter, undefined, adapter.options);
}
// return the adapter as provided
return adapter;
}
exports.default = loadAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AnalyticsAdapter.js | 77.78% | (21 / 27) | 50% | (5 / 10) | 50% | (4 / 8) | 72.73% | (8 / 11) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 2 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
var AnalyticsAdapter = exports.AnalyticsAdapter = function () {
function AnalyticsAdapter() {
_classCallCheck(this, AnalyticsAdapter);
}
_createClass(AnalyticsAdapter, [{
key: "appOpened",
/*
@param parameters: the analytics request body, analytics info will be in the dimensions property
@param req: the original http request
*/
value: function appOpened(parameters, req) {
return Promise.resolve({});
}
/*
@param eventName: the name of the custom eventName
@param parameters: the analytics request body, analytics info will be in the dimensions property
@param req: the original http request
*/
}, {
key: "trackEvent",
value: function trackEvent(eventName, parameters, req) {
return Promise.resolve({});
}
}]);
return AnalyticsAdapter;
}();
exports.default = AnalyticsAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AuthAdapter.js | 77.78% | (21 / 27) | 50% | (5 / 10) | 50% | (4 / 8) | 72.73% | (8 / 11) | |
| OAuth1Client.js | 16% | (16 / 100) | 0% | (0 / 38) | 0% | (0 / 18) | 16% | (16 / 100) | |
| facebook.js | 23.08% | (6 / 26) | 0% | (0 / 10) | 0% | (0 / 10) | 23.08% | (6 / 26) | |
| github.js | 30% | (6 / 20) | 0% | (0 / 4) | 0% | (0 / 9) | 30% | (6 / 20) | |
| google.js | 25.81% | (8 / 31) | 0% | (0 / 12) | 0% | (0 / 14) | 25.81% | (8 / 31) | |
| index.js | 43.1% | (25 / 58) | 8.82% | (3 / 34) | 9.09% | (1 / 11) | 42.11% | (24 / 57) | |
| instagram.js | 30% | (6 / 20) | 0% | (0 / 5) | 0% | (0 / 9) | 30% | (6 / 20) | |
| janraincapture.js | 33.33% | (7 / 21) | 0% | (0 / 5) | 0% | (0 / 9) | 33.33% | (7 / 21) | |
| janrainengage.js | 29.17% | (7 / 24) | 0% | (0 / 5) | 0% | (0 / 8) | 29.17% | (7 / 24) | |
| linkedin.js | 26.09% | (6 / 23) | 0% | (0 / 6) | 0% | (0 / 9) | 26.09% | (6 / 23) | |
| meetup.js | 30% | (6 / 20) | 0% | (0 / 4) | 0% | (0 / 9) | 30% | (6 / 20) | |
| qq.js | 24% | (6 / 25) | 0% | (0 / 8) | 0% | (0 / 9) | 24% | (6 / 25) | |
| spotify.js | 23.08% | (6 / 26) | 0% | (0 / 10) | 0% | (0 / 10) | 23.08% | (6 / 26) | |
| twitter.js | 22.58% | (7 / 31) | 0% | (0 / 12) | 0% | (0 / 5) | 22.58% | (7 / 31) | |
| vkontakte.js | 25% | (8 / 32) | 0% | (0 / 17) | 0% | (0 / 12) | 25% | (8 / 32) | |
| wechat.js | 30% | (6 / 20) | 0% | (0 / 2) | 0% | (0 / 9) | 30% | (6 / 20) | |
| weibo.js | 25% | (7 / 28) | 0% | (0 / 4) | 0% | (0 / 10) | 25% | (7 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 2 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
var AuthAdapter = exports.AuthAdapter = function () {
function AuthAdapter() {
_classCallCheck(this, AuthAdapter);
}
_createClass(AuthAdapter, [{
key: "validateAppId",
/*
@param appIds: the specified app ids in the configuration
@param authData: the client provided authData
@returns a promise that resolves if the applicationId is valid
*/
value: function validateAppId(appIds, authData) {
return Promise.resolve({});
}
/*
@param authData: the client provided authData
@param options: additional options
*/
}, {
key: "validateAuthData",
value: function validateAuthData(authData, options) {
return Promise.resolve({});
}
}]);
return AuthAdapter;
}();
exports.default = AuthAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var https = require('https'),
crypto = require('crypto');
var Parse = require('parse/node').Parse;
var OAuth = function OAuth(options) {
if (!options) {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'No options passed to OAuth');
}
this.consumer_key = options.consumer_key;
this.consumer_secret = options.consumer_secret;
this.auth_token = options.auth_token;
this.auth_token_secret = options.auth_token_secret;
this.host = options.host;
this.oauth_params = options.oauth_params || {};
};
OAuth.prototype.send = function (method, path, params, body) {
var request = this.buildRequest(method, path, params, body);
// Encode the body properly, the current Parse Implementation don't do it properly
return new Promise(function (resolve, reject) {
var httpRequest = https.request(request, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to make an OAuth request');
});
if (request.body) {
httpRequest.write(request.body);
}
httpRequest.end();
});
};
OAuth.prototype.buildRequest = function (method, path, params, body) {
if (path.indexOf("/") != 0) {
path = "/" + path;
}
if (params && Object.keys(params).length > 0) {
path += "?" + OAuth.buildParameterString(params);
}
var request = {
host: this.host,
path: path,
method: method.toUpperCase()
};
var oauth_params = this.oauth_params || {};
oauth_params.oauth_consumer_key = this.consumer_key;
if (this.auth_token) {
oauth_params["oauth_token"] = this.auth_token;
}
request = OAuth.signRequest(request, oauth_params, this.consumer_secret, this.auth_token_secret);
if (body && Object.keys(body).length > 0) {
request.body = OAuth.buildParameterString(body);
}
return request;
};
OAuth.prototype.get = function (path, params) {
return this.send("GET", path, params);
};
OAuth.prototype.post = function (path, params, body) {
return this.send("POST", path, params, body);
};
/*
Proper string %escape encoding
*/
OAuth.encode = function (str) {
// discuss at: http://phpjs.org/functions/rawurlencode/
// original by: Brett Zamir (http://brett-zamir.me)
// input by: travc
// input by: Brett Zamir (http://brett-zamir.me)
// input by: Michael Grier
// input by: Ratheous
// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// bugfixed by: Brett Zamir (http://brett-zamir.me)
// bugfixed by: Joris
// reimplemented by: Brett Zamir (http://brett-zamir.me)
// reimplemented by: Brett Zamir (http://brett-zamir.me)
// note: This reflects PHP 5.3/6.0+ behavior
// note: Please be aware that this function expects to encode into UTF-8 encoded strings, as found on
// note: pages served as UTF-8
// example 1: rawurlencode('Kevin van Zonneveld!');
// returns 1: 'Kevin%20van%20Zonneveld%21'
// example 2: rawurlencode('http://kevin.vanzonneveld.net/');
// returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
// example 3: rawurlencode('http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a');
// returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
str = (str + '').toString();
// Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current
// PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
};
OAuth.signatureMethod = "HMAC-SHA1";
OAuth.version = "1.0";
/*
Generate a nonce
*/
OAuth.nonce = function () {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 30; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}return text;
};
OAuth.buildParameterString = function (obj) {
// Sort keys and encode values
if (obj) {
var keys = Object.keys(obj).sort();
// Map key=value, join them by &
return keys.map(function (key) {
return key + "=" + OAuth.encode(obj[key]);
}).join("&");
}
return "";
};
/*
Build the signature string from the object
*/
OAuth.buildSignatureString = function (method, url, parameters) {
return [method.toUpperCase(), OAuth.encode(url), OAuth.encode(parameters)].join("&");
};
/*
Retuns encoded HMAC-SHA1 from key and text
*/
OAuth.signature = function (text, key) {
crypto = require("crypto");
return OAuth.encode(crypto.createHmac('sha1', key).update(text).digest('base64'));
};
OAuth.signRequest = function (request, oauth_parameters, consumer_secret, auth_token_secret) {
oauth_parameters = oauth_parameters || {};
// Set default values
if (!oauth_parameters.oauth_nonce) {
oauth_parameters.oauth_nonce = OAuth.nonce();
}
if (!oauth_parameters.oauth_timestamp) {
oauth_parameters.oauth_timestamp = Math.floor(new Date().getTime() / 1000);
}
if (!oauth_parameters.oauth_signature_method) {
oauth_parameters.oauth_signature_method = OAuth.signatureMethod;
}
if (!oauth_parameters.oauth_version) {
oauth_parameters.oauth_version = OAuth.version;
}
if (!auth_token_secret) {
auth_token_secret = "";
}
// Force GET method if unset
if (!request.method) {
request.method = "GET";
}
// Collect all the parameters in one signatureParameters object
var signatureParams = {};
var parametersToMerge = [request.params, request.body, oauth_parameters];
for (var i in parametersToMerge) {
var parameters = parametersToMerge[i];
for (var k in parameters) {
signatureParams[k] = parameters[k];
}
}
// Create a string based on the parameters
var parameterString = OAuth.buildParameterString(signatureParams);
// Build the signature string
var url = "https://" + request.host + "" + request.path;
var signatureString = OAuth.buildSignatureString(request.method, url, parameterString);
// Hash the signature string
var signatureKey = [OAuth.encode(consumer_secret), OAuth.encode(auth_token_secret)].join("&");
var signature = OAuth.signature(signatureString, signatureKey);
// Set the signature in the params
oauth_parameters.oauth_signature = signature;
if (!request.headers) {
request.headers = {};
}
// Set the authorization header
var authHeader = Object.keys(oauth_parameters).sort().map(function (key) {
var value = oauth_parameters[key];
return key + '="' + value + '"';
}).join(", ");
request.headers.Authorization = 'OAuth ' + authHeader;
// Set the content type header
request.headers["Content-Type"] = "application/x-www-form-urlencoded";
return request;
};
module.exports = OAuth;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the Facebook Graph API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return graphRequest('me?fields=id&access_token=' + authData.access_token).then(function (data) {
if (data && data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Facebook auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId(appIds, authData) {
var access_token = authData.access_token;
if (!appIds.length) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Facebook auth is not configured.');
}
return graphRequest('app?access_token=' + access_token).then(function (data) {
if (data && appIds.indexOf(data.id) != -1) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Facebook auth is invalid for this user.');
});
}
// A promisey wrapper for FB graph requests.
function graphRequest(path) {
return new Promise(function (resolve, reject) {
https.get('https://graph.facebook.com/v2.5/' + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Facebook.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the github API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request('user', authData.access_token).then(function (data) {
if (data && data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Github auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(path, access_token) {
return new Promise(function (resolve, reject) {
https.get({
host: 'api.github.com',
path: '/' + path,
headers: {
'Authorization': 'bearer ' + access_token,
'User-Agent': 'parse-server'
}
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Github.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the google API.
var https = require('https');
var Parse = require('parse/node').Parse;
function validateIdToken(id, token) {
return request("tokeninfo?id_token=" + token).then(function (response) {
if (response && (response.sub == id || response.user_id == id)) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.');
});
}
function validateAuthToken(id, token) {
return request("tokeninfo?access_token=" + token).then(function (response) {
if (response && (response.sub == id || response.user_id == id)) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.');
});
}
// Returns a promise that fulfills if this user id is valid.
function validateAuthData(authData) {
if (authData.id_token) {
return validateIdToken(authData.id, authData.id_token);
} else {
return validateAuthToken(authData.id, authData.access_token).then(function () {
// Validation with auth token worked
return;
}, function () {
// Try with the id_token param
return validateIdToken(authData.id, authData.access_token);
});
}
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(path) {
return new Promise(function (resolve, reject) {
https.get("https://www.googleapis.com/oauth2/v3/" + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Google.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var _AdapterLoader = require('../AdapterLoader');
var _AdapterLoader2 = _interopRequireDefault(_AdapterLoader);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var facebook = require('./facebook');
var instagram = require("./instagram");
var linkedin = require("./linkedin");
var meetup = require("./meetup");
var google = require("./google");
var github = require("./github");
var twitter = require("./twitter");
var spotify = require("./spotify");
var digits = require("./twitter"); // digits tokens are validated by twitter
var janrainengage = require("./janrainengage");
var janraincapture = require("./janraincapture");
var vkontakte = require("./vkontakte");
var qq = require("./qq");
var wechat = require("./wechat");
var weibo = require("./weibo");
var anonymous = {
validateAuthData: function validateAuthData() {
return Promise.resolve();
},
validateAppId: function validateAppId() {
return Promise.resolve();
}
};
var providers = {
facebook: facebook,
instagram: instagram,
linkedin: linkedin,
meetup: meetup,
google: google,
github: github,
twitter: twitter,
spotify: spotify,
anonymous: anonymous,
digits: digits,
janrainengage: janrainengage,
janraincapture: janraincapture,
vkontakte: vkontakte,
qq: qq,
wechat: wechat,
weibo: weibo
};
function authDataValidator(adapter, appIds, options) {
return function (authData) {
return adapter.validateAuthData(authData, options).then(function () {
if (appIds) {
return adapter.validateAppId(appIds, authData, options);
}
return Promise.resolve();
});
};
}
function loadAuthAdapter(provider, authOptions) {
var defaultAdapter = providers[provider];
var adapter = Object.assign({}, defaultAdapter);
var providerOptions = authOptions[provider];
if (!defaultAdapter && !providerOptions) {
return;
}
var appIds = providerOptions ? providerOptions.appIds : undefined;
// Try the configuration methods
if (providerOptions) {
var optionalAdapter = (0, _AdapterLoader2.default)(providerOptions, undefined, providerOptions);
if (optionalAdapter) {
['validateAuthData', 'validateAppId'].forEach(function (key) {
if (optionalAdapter[key]) {
adapter[key] = optionalAdapter[key];
}
});
}
}
if (!adapter.validateAuthData || !adapter.validateAppId) {
return;
}
return { adapter: adapter, appIds: appIds, providerOptions: providerOptions };
}
module.exports = function () {
var authOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var enableAnonymousUsers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var _enableAnonymousUsers = enableAnonymousUsers;
var setEnableAnonymousUsers = function setEnableAnonymousUsers(enable) {
_enableAnonymousUsers = enable;
};
// To handle the test cases on configuration
var getValidatorForProvider = function getValidatorForProvider(provider) {
if (provider === 'anonymous' && !_enableAnonymousUsers) {
return;
}
var _loadAuthAdapter = loadAuthAdapter(provider, authOptions),
adapter = _loadAuthAdapter.adapter,
appIds = _loadAuthAdapter.appIds,
providerOptions = _loadAuthAdapter.providerOptions;
return authDataValidator(adapter, appIds, providerOptions);
};
return Object.freeze({
getValidatorForProvider: getValidatorForProvider,
setEnableAnonymousUsers: setEnableAnonymousUsers
});
};
module.exports.loadAuthAdapter = loadAuthAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the instagram API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request("users/self/?access_token=" + authData.access_token).then(function (response) {
if (response && response.data && response.data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Instagram auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(path) {
return new Promise(function (resolve, reject) {
https.get("https://api.instagram.com/v1/" + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Instagram.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the Janrain Capture API.
var https = require('https');
var Parse = require('parse/node').Parse;
var querystring = require('querystring');
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, options) {
return request(options.janrain_capture_host, authData.access_token).then(function (data) {
//successful response will have a "stat" (status) of 'ok' and a result node that stores the uuid, because that's all we asked for
//see: https://docs.janrain.com/api/registration/entity/#entity
if (data && data.stat == 'ok' && data.result == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Janrain capture auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
//no-op
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(host, access_token) {
var query_string_data = querystring.stringify({
'access_token': access_token,
'attribute_name': 'uuid' // we only need to pull the uuid for this access token to make sure it matches
});
return new Promise(function (resolve, reject) {
https.get({
host: host,
path: '/entity?' + query_string_data
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
resolve(JSON.parse(data));
});
}).on('error', function () {
reject('Failed to validate this access token with Janrain capture.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the Janrain Engage API.
var https = require('https');
var Parse = require('parse/node').Parse;
var querystring = require('querystring');
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, options) {
return request(options.api_key, authData.auth_token).then(function (data) {
//successful response will have a "stat" (status) of 'ok' and a profile node with an identifier
//see: http://developers.janrain.com/overview/social-login/identity-providers/user-profile-data/#normalized-user-profile-data
if (data && data.stat == 'ok' && data.profile.identifier == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Janrain engage auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
//no-op
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(api_key, auth_token) {
var post_data = querystring.stringify({
'token': auth_token,
'apiKey': api_key,
'format': 'json'
});
var post_options = {
host: 'rpxnow.com',
path: '/api/v2/auth_info',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
return new Promise(function (resolve) {
// Create the post request.
var post_req = https.request(post_options, function (res) {
var data = '';
res.setEncoding('utf8');
// Append data as we receive it from the Janrain engage server.
res.on('data', function (d) {
data += d;
});
// Once we have all the data, we can parse it and return the data we want.
res.on('end', function () {
resolve(JSON.parse(data));
});
});
post_req.write(post_data);
post_req.end();
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the linkedin API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request('people/~:(id)', authData.access_token, authData.is_mobile_sdk).then(function (data) {
if (data && data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Linkedin auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(path, access_token, is_mobile_sdk) {
var headers = {
'Authorization': 'Bearer ' + access_token,
'x-li-format': 'json'
};
if (is_mobile_sdk) {
headers['x-li-src'] = 'msdk';
}
return new Promise(function (resolve, reject) {
https.get({
host: 'api.linkedin.com',
path: '/v1/' + path,
headers: headers
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Linkedin.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the meetup API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request('member/self', authData.access_token).then(function (data) {
if (data && data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Meetup auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(path, access_token) {
return new Promise(function (resolve, reject) {
https.get({
host: 'api.meetup.com',
path: '/2/' + path,
headers: {
'Authorization': 'bearer ' + access_token
}
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Meetup.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the qq Graph API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return graphRequest('me?access_token=' + authData.access_token).then(function (data) {
if (data && data.openid == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'qq auth is invalid for this user.');
});
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for qq graph requests.
function graphRequest(path) {
return new Promise(function (resolve, reject) {
https.get('https://graph.qq.com/oauth2.0/' + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
var starPos = data.indexOf("(");
var endPos = data.indexOf(")");
if (starPos == -1 || endPos == -1) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'qq auth is invalid for this user.');
}
data = data.substring(starPos + 1, endPos - 1);
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with qq.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the Spotify API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request('me', authData.access_token).then(function (data) {
if (data && data.id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Spotify auth is invalid for this user.');
});
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId(appIds, authData) {
var access_token = authData.access_token;
if (!appIds.length) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Spotify auth is not configured.');
}
return request('me', access_token).then(function (data) {
if (data && appIds.indexOf(data.id) != -1) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Spotify auth is invalid for this user.');
});
}
// A promisey wrapper for Spotify API requests.
function request(path, access_token) {
return new Promise(function (resolve, reject) {
https.get({
host: 'api.spotify.com',
path: '/v1/' + path,
headers: {
'Authorization': 'Bearer ' + access_token
}
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Spotify.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the twitter API.
var OAuth = require('./OAuth1Client');
var Parse = require('parse/node').Parse;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, options) {
if (!options) {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Twitter auth configuration missing');
}
options = handleMultipleConfigurations(authData, options);
var client = new OAuth(options);
client.host = "api.twitter.com";
client.auth_token = authData.auth_token;
client.auth_token_secret = authData.auth_token_secret;
return client.get("/1.1/account/verify_credentials.json").then(function (data) {
if (data && data.id_str == '' + authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Twitter auth is invalid for this user.');
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
function handleMultipleConfigurations(authData, options) {
if (Array.isArray(options)) {
var consumer_key = authData.consumer_key;
if (!consumer_key) {
logger.error('Twitter Auth', 'Multiple twitter configurations are available, by no consumer_key was sent by the client.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Twitter auth is invalid for this user.');
}
options = options.filter(function (option) {
return option.consumer_key == consumer_key;
});
if (options.length == 0) {
logger.error('Twitter Auth', 'Cannot find a configuration for the provided consumer_key');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Twitter auth is invalid for this user.');
}
options = options[0];
}
return options;
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData,
handleMultipleConfigurations: handleMultipleConfigurations
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the vkontakte API.
var https = require('https');
var Parse = require('parse/node').Parse;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, params) {
return vkOAuth2Request(params).then(function (response) {
if (response && response && response.access_token) {
return request("api.vk.com", "method/secure.checkToken?token=" + authData.access_token + "&client_secret=" + params.appSecret + "&access_token=" + response.access_token).then(function (response) {
if (response && response.response && response.response.user_id == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Vk auth is invalid for this user.');
});
}
logger.error('Vk Auth', 'Vk appIds or appSecret is incorrect.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Vk appIds or appSecret is incorrect.');
});
}
function vkOAuth2Request(params) {
var promise = new Parse.Promise();
return promise.then(function () {
if (!params || !params.appIds || !params.appIds.length || !params.appSecret || !params.appSecret.length) {
logger.error('Vk Auth', 'Vk auth is not configured. Missing appIds or appSecret.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Vk auth is not configured. Missing appIds or appSecret.');
}
return request("oauth.vk.com", "access_token?client_id=" + params.appIds + "&client_secret=" + params.appSecret + "&v=5.59&grant_type=client_credentials");
});
}
// Returns a promise that fulfills iff this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for api requests
function request(host, path) {
return new Promise(function (resolve, reject) {
https.get("https://" + host + "/" + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with Vk.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the WeChat Graph API.
var https = require('https');
var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return graphRequest('auth?access_token=' + authData.access_token + '&openid=' + authData.id).then(function (data) {
if (data.errcode == 0) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'qq auth is invalid for this user.');
});
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for WeChat graph requests.
function graphRequest(path) {
return new Promise(function (resolve, reject) {
https.get('https://api.weixin.qq.com/sns/' + path, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function () {
reject('Failed to validate this access token with weixin.');
});
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 | 'use strict';
// Helper functions for accessing the weibo Graph API.
var https = require('https');
var Parse = require('parse/node').Parse;
var querystring = require('querystring');
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return graphRequest(authData.access_token).then(function (data) {
if (data && data.uid == authData.id) {
return;
}
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'weibo auth is invalid for this user.');
});
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId() {
return Promise.resolve();
}
// A promisey wrapper for weibo graph requests.
function graphRequest(access_token) {
return new Promise(function (resolve, reject) {
var postData = querystring.stringify({
"access_token": access_token
});
var options = {
hostname: 'api.weibo.com',
path: '/oauth2/get_token_info',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var req = https.request(options, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
data = JSON.parse(data);
resolve(data);
});
res.on('error', function () {
reject('Failed to validate this access token with weibo.');
});
});
req.on('error', function () {
reject('Failed to validate this access token with weibo.');
});
req.write(postData);
req.end();
});
}
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| CacheAdapter.js | 83.33% | (20 / 24) | 50% | (5 / 10) | 40% | (4 / 10) | 87.5% | (7 / 8) | |
| InMemoryCache.js | 51.92% | (27 / 52) | 21.88% | (7 / 32) | 54.55% | (6 / 11) | 36.11% | (13 / 36) | |
| InMemoryCacheAdapter.js | 57.5% | (23 / 40) | 41.67% | (5 / 12) | 36.36% | (4 / 11) | 41.67% | (10 / 24) | |
| NullCacheAdapter.js | 70% | (21 / 30) | 50% | (5 / 10) | 36.36% | (4 / 11) | 57.14% | (8 / 14) | |
| RedisCacheAdapter.js | 37.97% | (30 / 79) | 28.13% | (9 / 32) | 20% | (5 / 25) | 25.81% | (16 / 62) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1 4 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
var CacheAdapter = exports.CacheAdapter = function () {
function CacheAdapter() {
_classCallCheck(this, CacheAdapter);
}
_createClass(CacheAdapter, [{
key: "get",
/**
* Get a value in the cache
* @param key Cache key to get
* @return Promise that will eventually resolve to the value in the cache.
*/
value: function get(key) {}
/**
* Set a value in the cache
* @param key Cache key to set
* @param value Value to set the key
* @param ttl Optional TTL
*/
}, {
key: "put",
value: function put(key, value, ttl) {}
/**
* Remove a value from the cache.
* @param key Cache key to remove
*/
}, {
key: "del",
value: function del(key) {}
/**
* Empty a cache
*/
}, {
key: "clear",
value: function clear() {}
}]);
return CacheAdapter;
}();
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1 4 1 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var DEFAULT_CACHE_TTL = 5 * 1000;
var InMemoryCache = exports.InMemoryCache = function () {
function InMemoryCache(_ref) {
var _ref$ttl = _ref.ttl,
ttl = _ref$ttl === undefined ? DEFAULT_CACHE_TTL : _ref$ttl;
_classCallCheck(this, InMemoryCache);
this.ttl = ttl;
this.cache = Object.create(null);
}
_createClass(InMemoryCache, [{
key: "get",
value: function get(key) {
var record = this.cache[key];
if (record == null) {
return null;
}
// Has Record and isnt expired
if (isNaN(record.expire) || record.expire >= Date.now()) {
return record.value;
}
// Record has expired
delete this.cache[key];
return null;
}
}, {
key: "put",
value: function put(key, value) {
var _this = this;
var ttl = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.ttl;
if (ttl < 0 || isNaN(ttl)) {
ttl = NaN;
}
var record = {
value: value,
expire: ttl + Date.now()
};
if (!isNaN(record.expire)) {
record.timeout = setTimeout(function () {
_this.del(key);
}, ttl);
}
this.cache[key] = record;
}
}, {
key: "del",
value: function del(key) {
var record = this.cache[key];
if (record == null) {
return;
}
if (record.timeout) {
clearTimeout(record.timeout);
}
delete this.cache[key];
}
}, {
key: "clear",
value: function clear() {
this.cache = Object.create(null);
}
}]);
return InMemoryCache;
}();
exports.default = InMemoryCache;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 4 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.InMemoryCacheAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _InMemoryCache = require('./InMemoryCache');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var InMemoryCacheAdapter = exports.InMemoryCacheAdapter = function () {
function InMemoryCacheAdapter(ctx) {
_classCallCheck(this, InMemoryCacheAdapter);
this.cache = new _InMemoryCache.InMemoryCache(ctx);
}
_createClass(InMemoryCacheAdapter, [{
key: 'get',
value: function get(key) {
var _this = this;
return new Promise(function (resolve) {
var record = _this.cache.get(key);
if (record == null) {
return resolve(null);
}
return resolve(JSON.parse(record));
});
}
}, {
key: 'put',
value: function put(key, value, ttl) {
this.cache.put(key, JSON.stringify(value), ttl);
return Promise.resolve();
}
}, {
key: 'del',
value: function del(key) {
this.cache.del(key);
return Promise.resolve();
}
}, {
key: 'clear',
value: function clear() {
this.cache.clear();
return Promise.resolve();
}
}]);
return InMemoryCacheAdapter;
}();
exports.default = InMemoryCacheAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 4 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var NullCacheAdapter = exports.NullCacheAdapter = function () {
function NullCacheAdapter() {
_classCallCheck(this, NullCacheAdapter);
}
_createClass(NullCacheAdapter, [{
key: "get",
value: function get() {
return new Promise(function (resolve) {
return resolve(null);
});
}
}, {
key: "put",
value: function put() {
return Promise.resolve();
}
}, {
key: "del",
value: function del() {
return Promise.resolve();
}
}, {
key: "clear",
value: function clear() {
return Promise.resolve();
}
}]);
return NullCacheAdapter;
}();
exports.default = NullCacheAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1 1 4 1 1 1 1 2 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RedisCacheAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _redis = require('redis');
var _redis2 = _interopRequireDefault(_redis);
var _logger = require('../../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var DEFAULT_REDIS_TTL = 30 * 1000; // 30 seconds in milliseconds
function debug() {
_logger2.default.debug.apply(_logger2.default, ['RedisCacheAdapter'].concat(Array.prototype.slice.call(arguments)));
}
var RedisCacheAdapter = exports.RedisCacheAdapter = function () {
function RedisCacheAdapter(redisCtx) {
var ttl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_REDIS_TTL;
_classCallCheck(this, RedisCacheAdapter);
this.client = _redis2.default.createClient(redisCtx);
this.p = Promise.resolve();
this.ttl = ttl;
}
_createClass(RedisCacheAdapter, [{
key: 'get',
value: function get(key) {
var _this = this;
debug('get', key);
this.p = this.p.then(function () {
return new Promise(function (resolve) {
_this.client.get(key, function (err, res) {
debug('-> get', key, res);
if (!res) {
return resolve(null);
}
resolve(JSON.parse(res));
});
});
});
return this.p;
}
}, {
key: 'put',
value: function put(key, value) {
var _this2 = this;
var ttl = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.ttl;
value = JSON.stringify(value);
debug('put', key, value, ttl);
if (ttl === 0) {
return this.p; // ttl of zero is a logical no-op, but redis cannot set expire time of zero
}
if (ttl < 0 || isNaN(ttl)) {
ttl = DEFAULT_REDIS_TTL;
}
this.p = this.p.then(function () {
return new Promise(function (resolve) {
if (ttl === Infinity) {
_this2.client.set(key, value, function () {
resolve();
});
} else {
_this2.client.psetex(key, ttl, value, function () {
resolve();
});
}
});
});
return this.p;
}
}, {
key: 'del',
value: function del(key) {
var _this3 = this;
debug('del', key);
this.p = this.p.then(function () {
return new Promise(function (resolve) {
_this3.client.del(key, function () {
resolve();
});
});
});
return this.p;
}
}, {
key: 'clear',
value: function clear() {
var _this4 = this;
debug('clear');
this.p = this.p.then(function () {
return new Promise(function (resolve) {
_this4.client.flushdb(function () {
resolve();
});
});
});
return this.p;
}
}]);
return RedisCacheAdapter;
}();
exports.default = RedisCacheAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| MailAdapter.js | 84% | (21 / 25) | 50% | (5 / 10) | 57.14% | (4 / 7) | 88.89% | (8 / 9) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
/*
Mail Adapter prototype
A MailAdapter should implement at least sendMail()
*/
var MailAdapter = exports.MailAdapter = function () {
function MailAdapter() {
_classCallCheck(this, MailAdapter);
}
_createClass(MailAdapter, [{
key: "sendMail",
/*
* A method for sending mail
* @param options would have the parameters
* - to: the recipient
* - text: the raw text of the message
* - subject: the subject of the email
*/
value: function sendMail(options) {}
/* You can implement those methods if you want
* to provide HTML templates etc...
*/
// sendVerificationEmail({ link, appName, user }) {}
// sendPasswordResetEmail({ link, appName, user }) {}
}]);
return MailAdapter;
}();
exports.default = MailAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| FilesAdapter.js | 84% | (21 / 25) | 50% | (5 / 10) | 40% | (4 / 10) | 88.89% | (8 / 9) | |
| GridStoreAdapter.js | 50% | (35 / 70) | 35.9% | (14 / 39) | 23.08% | (6 / 26) | 37.78% | (17 / 45) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 4 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
// Files Adapter
//
// Allows you to change the file storage mechanism.
//
// Adapter classes must implement the following functions:
// * createFile(config, filename, data)
// * getFileData(config, filename)
// * getFileLocation(config, request, filename)
//
// Default is GridStoreAdapter, which requires mongo
// and for the API server to be using the DatabaseController with Mongo
// database adapter.
var FilesAdapter = exports.FilesAdapter = function () {
function FilesAdapter() {
_classCallCheck(this, FilesAdapter);
}
_createClass(FilesAdapter, [{
key: "createFile",
/* This method is responsible to store the file in order to be retrieved later by its file name
*
* @param filename the filename to save
* @param data the buffer of data from the file
* @param contentType the supposed contentType
* @discussion the contentType can be undefined if the controller was not able to determine it
*
* @return a promise that should fail if the storage didn't succeed
*
*/
value: function createFile(filename, data, contentType) {}
}, {
key: "deleteFile",
value: function deleteFile(filename) {}
}, {
key: "getFileData",
value: function getFileData(filename) {}
}, {
key: "getFileLocation",
value: function getFileLocation(config, filename) {}
}]);
return FilesAdapter;
}();
exports.default = FilesAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 1 1 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GridStoreAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _mongodb = require('mongodb');
var _FilesAdapter2 = require('./FilesAdapter');
var _defaults = require('../../defaults');
var _defaults2 = _interopRequireDefault(_defaults);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
GridStoreAdapter
Stores files in Mongo using GridStore
Requires the database adapter to be based on mongoclient
weak
*/
var GridStoreAdapter = exports.GridStoreAdapter = function (_FilesAdapter) {
_inherits(GridStoreAdapter, _FilesAdapter);
function GridStoreAdapter() {
var mongoDatabaseURI = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _defaults2.default.DefaultMongoURI;
_classCallCheck(this, GridStoreAdapter);
var _this = _possibleConstructorReturn(this, (GridStoreAdapter.__proto__ || Object.getPrototypeOf(GridStoreAdapter)).call(this));
_this._databaseURI = mongoDatabaseURI;
return _this;
}
_createClass(GridStoreAdapter, [{
key: '_connect',
value: function _connect() {
if (!this._connectionPromise) {
this._connectionPromise = _mongodb.MongoClient.connect(this._databaseURI);
}
return this._connectionPromise;
}
// For a given config object, filename, and data, store a file
// Returns a promise
}, {
key: 'createFile',
value: function createFile(filename, data) {
return this._connect().then(function (database) {
var gridStore = new _mongodb.GridStore(database, filename, 'w');
return gridStore.open();
}).then(function (gridStore) {
return gridStore.write(data);
}).then(function (gridStore) {
return gridStore.close();
});
}
}, {
key: 'deleteFile',
value: function deleteFile(filename) {
return this._connect().then(function (database) {
var gridStore = new _mongodb.GridStore(database, filename, 'r');
return gridStore.open();
}).then(function (gridStore) {
return gridStore.unlink();
}).then(function (gridStore) {
return gridStore.close();
});
}
}, {
key: 'getFileData',
value: function getFileData(filename) {
return this._connect().then(function (database) {
return _mongodb.GridStore.exist(database, filename).then(function () {
var gridStore = new _mongodb.GridStore(database, filename, 'r');
return gridStore.open();
});
}).then(function (gridStore) {
return gridStore.read();
});
}
}, {
key: 'getFileLocation',
value: function getFileLocation(config, filename) {
return config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename);
}
}, {
key: 'getFileStream',
value: function getFileStream(filename) {
return this._connect().then(function (database) {
return _mongodb.GridStore.exist(database, filename).then(function () {
var gridStore = new _mongodb.GridStore(database, filename, 'r');
return gridStore.open();
});
});
}
}]);
return GridStoreAdapter;
}(_FilesAdapter2.FilesAdapter);
exports.default = GridStoreAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| LoggerAdapter.js | 92% | (23 / 25) | 60% | (6 / 10) | 85.71% | (6 / 7) | 100% | (9 / 9) | |
| WinstonLogger.js | 78.79% | (52 / 66) | 55.88% | (19 / 34) | 42.86% | (3 / 7) | 78.46% | (51 / 65) | |
| WinstonLoggerAdapter.js | 63.08% | (41 / 65) | 33.33% | (17 / 51) | 64.29% | (9 / 14) | 51.22% | (21 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
// Logger Adapter
//
// Allows you to change the logger mechanism
//
// Adapter classes must implement the following functions:
// * log() {}
// * query(options, callback) /* optional */
// Default is WinstonLoggerAdapter.js
var LoggerAdapter = exports.LoggerAdapter = function () {
function LoggerAdapter(options) {
_classCallCheck(this, LoggerAdapter);
}
_createClass(LoggerAdapter, [{
key: "log",
value: function log(level, message) /* meta */{}
}]);
return LoggerAdapter;
}();
exports.default = LoggerAdapter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.logger = undefined;
exports.configureLogger = configureLogger;
exports.addTransport = addTransport;
exports.removeTransport = removeTransport;
var _winston = require('winston');
var _winston2 = _interopRequireDefault(_winston);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _winstonDailyRotateFile = require('winston-daily-rotate-file');
var _winstonDailyRotateFile2 = _interopRequireDefault(_winstonDailyRotateFile);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _defaults = require('../../defaults');
var _defaults2 = _interopRequireDefault(_defaults);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var logger = new _winston2.default.Logger();
var additionalTransports = [];
function updateTransports(options) {
var transports = Object.assign({}, logger.transports);
Eif (options) {
var silent = options.silent;
delete options.silent;
Iif (_lodash2.default.isNull(options.dirname)) {
delete transports['parse-server'];
delete transports['parse-server-error'];
} else Eif (!_lodash2.default.isUndefined(options.dirname)) {
transports['parse-server'] = new _winstonDailyRotateFile2.default(Object.assign({}, {
filename: 'parse-server.info',
name: 'parse-server'
}, options, { timestamp: true }));
transports['parse-server-error'] = new _winstonDailyRotateFile2.default(Object.assign({}, {
filename: 'parse-server.err',
name: 'parse-server-error'
}, options, { level: 'error', timestamp: true }));
}
transports.console = new _winston2.default.transports.Console(Object.assign({
colorize: true,
name: 'console',
silent: silent
}, options));
}
// Mount the additional transports
additionalTransports.forEach(function (transport) {
transports[transport.name] = transport;
});
logger.configure({
transports: _lodash2.default.values(transports)
});
}
function configureLogger() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$logsFolder = _ref.logsFolder,
logsFolder = _ref$logsFolder === undefined ? _defaults2.default.logsFolder : _ref$logsFolder,
_ref$jsonLogs = _ref.jsonLogs,
jsonLogs = _ref$jsonLogs === undefined ? _defaults2.default.jsonLogs : _ref$jsonLogs,
_ref$logLevel = _ref.logLevel,
logLevel = _ref$logLevel === undefined ? _winston2.default.level : _ref$logLevel,
_ref$verbose = _ref.verbose,
verbose = _ref$verbose === undefined ? _defaults2.default.verbose : _ref$verbose,
_ref$silent = _ref.silent,
silent = _ref$silent === undefined ? _defaults2.default.silent : _ref$silent;
Iif (verbose) {
logLevel = 'verbose';
}
_winston2.default.level = logLevel;
var options = {};
Eif (logsFolder) {
Eif (!_path2.default.isAbsolute(logsFolder)) {
logsFolder = _path2.default.resolve(process.cwd(), logsFolder);
}
try {
_fs2.default.mkdirSync(logsFolder);
} catch (e) {/* */}
}
options.dirname = logsFolder;
options.level = logLevel;
options.silent = silent;
Iif (jsonLogs) {
options.json = true;
options.stringify = true;
}
updateTransports(options);
}
function addTransport(transport) {
additionalTransports.push(transport);
updateTransports();
}
function removeTransport(transport) {
var transportName = typeof transport == 'string' ? transport : transport.name;
var transports = Object.assign({}, logger.transports);
delete transports[transportName];
logger.configure({
transports: _lodash2.default.values(transports)
});
_lodash2.default.remove(additionalTransports, function (transport) {
return transport.name === transportName;
});
}
exports.logger = logger;
exports.default = logger;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WinstonLoggerAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _LoggerAdapter2 = require('./LoggerAdapter');
var _WinstonLogger = require('./WinstonLogger');
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { Iif (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
var WinstonLoggerAdapter = exports.WinstonLoggerAdapter = function (_LoggerAdapter) {
_inherits(WinstonLoggerAdapter, _LoggerAdapter);
function WinstonLoggerAdapter(options) {
_classCallCheck(this, WinstonLoggerAdapter);
var _this = _possibleConstructorReturn(this, (WinstonLoggerAdapter.__proto__ || Object.getPrototypeOf(WinstonLoggerAdapter)).call(this));
Eif (options) {
(0, _WinstonLogger.configureLogger)(options);
}
return _this;
}
_createClass(WinstonLoggerAdapter, [{
key: 'log',
value: function log() {
return _WinstonLogger.logger.log.apply(_WinstonLogger.logger, arguments);
}
}, {
key: 'addTransport',
value: function addTransport(transport) {
// Note that this is calling addTransport
// from logger. See import - confusing.
// but this is not recursive.
(0, _WinstonLogger.addTransport)(transport);
}
// custom query as winston is currently limited
}, {
key: 'query',
value: function query(options) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
if (!options) {
options = {};
}
// defaults to 7 days prior
var from = options.from || new Date(Date.now() - 7 * MILLISECONDS_IN_A_DAY);
var until = options.until || new Date();
var limit = options.size || 10;
var order = options.order || 'desc';
var level = options.level || 'info';
var queryOptions = {
from: from,
until: until,
limit: limit,
order: order
};
return new Promise(function (resolve, reject) {
_WinstonLogger.logger.query(queryOptions, function (err, res) {
if (err) {
callback(err);
return reject(err);
}
if (level == 'error') {
callback(res['parse-server-error']);
resolve(res['parse-server-error']);
} else {
callback(res['parse-server']);
resolve(res['parse-server']);
}
});
});
}
}]);
return WinstonLoggerAdapter;
}(_LoggerAdapter2.LoggerAdapter);
exports.default = WinstonLoggerAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| EventEmitterMQ.js | 61.43% | (43 / 70) | 40% | (14 / 35) | 38.89% | (7 / 18) | 55.56% | (25 / 45) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EventEmitterMQ = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var emitter = new _events2.default.EventEmitter();
var subscriptions = new Map();
function _unsubscribe(channel) {
if (!subscriptions.has(channel)) {
//console.log('No channel to unsub from');
return;
}
//console.log('unsub ', channel);
emitter.removeListener(channel, subscriptions.get(channel));
subscriptions.delete(channel);
}
var Publisher = function () {
function Publisher(emitter) {
_classCallCheck(this, Publisher);
this.emitter = emitter;
}
_createClass(Publisher, [{
key: 'publish',
value: function publish(channel, message) {
this.emitter.emit(channel, message);
}
}]);
return Publisher;
}();
var Consumer = function (_events$EventEmitter) {
_inherits(Consumer, _events$EventEmitter);
function Consumer(emitter) {
_classCallCheck(this, Consumer);
var _this = _possibleConstructorReturn(this, (Consumer.__proto__ || Object.getPrototypeOf(Consumer)).call(this));
_this.emitter = emitter;
return _this;
}
_createClass(Consumer, [{
key: 'subscribe',
value: function subscribe(channel) {
var _this2 = this;
_unsubscribe(channel);
var handler = function handler(message) {
_this2.emit('message', channel, message);
};
subscriptions.set(channel, handler);
this.emitter.on(channel, handler);
}
}, {
key: 'unsubscribe',
value: function unsubscribe(channel) {
_unsubscribe(channel);
}
}]);
return Consumer;
}(_events2.default.EventEmitter);
function createPublisher() {
return new Publisher(emitter);
}
function createSubscriber() {
return new Consumer(emitter);
}
var EventEmitterMQ = {
createPublisher: createPublisher,
createSubscriber: createSubscriber
};
exports.EventEmitterMQ = EventEmitterMQ;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| EventEmitterPubSub.js | 80.6% | (54 / 67) | 54.29% | (19 / 35) | 70.59% | (12 / 17) | 78.57% | (33 / 42) | |
| RedisPubSub.js | 71.43% | (10 / 14) | 75% | (3 / 4) | 33.33% | (1 / 3) | 69.23% | (9 / 13) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EventEmitterPubSub = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _possibleConstructorReturn(self, call) { Iif (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var emitter = new _events2.default.EventEmitter();
var Publisher = function () {
function Publisher(emitter) {
_classCallCheck(this, Publisher);
this.emitter = emitter;
}
_createClass(Publisher, [{
key: 'publish',
value: function publish(channel, message) {
this.emitter.emit(channel, message);
}
}]);
return Publisher;
}();
var Subscriber = function (_events$EventEmitter) {
_inherits(Subscriber, _events$EventEmitter);
function Subscriber(emitter) {
_classCallCheck(this, Subscriber);
var _this = _possibleConstructorReturn(this, (Subscriber.__proto__ || Object.getPrototypeOf(Subscriber)).call(this));
_this.emitter = emitter;
_this.subscriptions = new Map();
return _this;
}
_createClass(Subscriber, [{
key: 'subscribe',
value: function subscribe(channel) {
var _this2 = this;
var handler = function handler(message) {
_this2.emit('message', channel, message);
};
this.subscriptions.set(channel, handler);
this.emitter.on(channel, handler);
}
}, {
key: 'unsubscribe',
value: function unsubscribe(channel) {
if (!this.subscriptions.has(channel)) {
return;
}
this.emitter.removeListener(channel, this.subscriptions.get(channel));
this.subscriptions.delete(channel);
}
}]);
return Subscriber;
}(_events2.default.EventEmitter);
function createPublisher() {
return new Publisher(emitter);
}
function createSubscriber() {
return new Subscriber(emitter);
}
var EventEmitterPubSub = {
createPublisher: createPublisher,
createSubscriber: createSubscriber
};
exports.EventEmitterPubSub = EventEmitterPubSub;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RedisPubSub = undefined;
var _redis = require('redis');
var _redis2 = _interopRequireDefault(_redis);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createPublisher(_ref) {
var redisURL = _ref.redisURL;
return _redis2.default.createClient(redisURL, { no_ready_check: true });
}
function createSubscriber(_ref2) {
var redisURL = _ref2.redisURL;
return _redis2.default.createClient(redisURL, { no_ready_check: true });
}
var RedisPubSub = {
createPublisher: createPublisher,
createSubscriber: createSubscriber
};
exports.RedisPubSub = RedisPubSub;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| PushAdapter.js | 80.77% | (21 / 26) | 50% | (5 / 10) | 50% | (4 / 8) | 80% | (8 / 10) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 2 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*eslint no-unused-vars: "off"*/
// Push Adapter
//
// Allows you to change the push notification mechanism.
//
// Adapter classes must implement the following functions:
// * getValidPushTypes()
// * send(devices, installations, pushStatus)
//
// Default is ParsePushAdapter, which uses GCM for
// android push and APNS for ios push.
var PushAdapter = exports.PushAdapter = function () {
function PushAdapter() {
_classCallCheck(this, PushAdapter);
}
_createClass(PushAdapter, [{
key: "send",
value: function send(body, installations, pushStatus) {}
/**
* Get an array of valid push types.
* @returns {Array} An array of valid push types
*/
}, {
key: "getValidPushTypes",
value: function getValidPushTypes() {
return [];
}
}]);
return PushAdapter;
}();
exports.default = PushAdapter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| MongoCollection.js | 36.51% | (23 / 63) | 14.71% | (5 / 34) | 19.05% | (4 / 21) | 21.28% | (10 / 47) | |
| MongoSchemaCollection.js | 32.77% | (39 / 119) | 17.24% | (10 / 58) | 17.24% | (5 / 29) | 27.17% | (25 / 92) | |
| MongoStorageAdapter.js | 19.73% | (44 / 223) | 17.31% | (9 / 52) | 5.75% | (5 / 87) | 15.15% | (30 / 198) | |
| MongoTransform.js | 6.4% | (32 / 500) | 1.63% | (8 / 492) | 2.13% | (1 / 47) | 6.31% | (31 / 491) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | 1 11 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var mongodb = require('mongodb');
var Collection = mongodb.Collection;
var MongoCollection = function () {
function MongoCollection(mongoCollection) {
_classCallCheck(this, MongoCollection);
this._mongoCollection = mongoCollection;
}
// Does a find with "smart indexing".
// Currently this just means, if it needs a geoindex and there is
// none, then build the geoindex.
// This could be improved a lot but it's not clear if that's a good
// idea. Or even if this behavior is a good idea.
_createClass(MongoCollection, [{
key: 'find',
value: function find(query) {
var _this = this;
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
skip = _ref.skip,
limit = _ref.limit,
sort = _ref.sort,
keys = _ref.keys,
maxTimeMS = _ref.maxTimeMS;
return this._rawFind(query, { skip: skip, limit: limit, sort: sort, keys: keys, maxTimeMS: maxTimeMS }).catch(function (error) {
// Check for "no geoindex" error
if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) {
throw error;
}
// Figure out what key needs an index
var key = error.message.match(/field=([A-Za-z_0-9]+) /)[1];
if (!key) {
throw error;
}
var index = {};
index[key] = '2d';
return _this._mongoCollection.createIndex(index)
// Retry, but just once.
.then(function () {
return _this._rawFind(query, { skip: skip, limit: limit, sort: sort, keys: keys, maxTimeMS: maxTimeMS });
});
});
}
}, {
key: '_rawFind',
value: function _rawFind(query) {
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
skip = _ref2.skip,
limit = _ref2.limit,
sort = _ref2.sort,
keys = _ref2.keys,
maxTimeMS = _ref2.maxTimeMS;
var findOperation = this._mongoCollection.find(query, { skip: skip, limit: limit, sort: sort });
if (keys) {
findOperation = findOperation.project(keys);
}
if (maxTimeMS) {
findOperation = findOperation.maxTimeMS(maxTimeMS);
}
return findOperation.toArray();
}
}, {
key: 'count',
value: function count(query) {
var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
skip = _ref3.skip,
limit = _ref3.limit,
sort = _ref3.sort,
maxTimeMS = _ref3.maxTimeMS;
var countOperation = this._mongoCollection.count(query, { skip: skip, limit: limit, sort: sort, maxTimeMS: maxTimeMS });
return countOperation;
}
}, {
key: 'insertOne',
value: function insertOne(object) {
return this._mongoCollection.insertOne(object);
}
// Atomically updates data in the database for a single (first) object that matched the query
// If there is nothing that matches the query - does insert
// Postgres Note: `INSERT ... ON CONFLICT UPDATE` that is available since 9.5.
}, {
key: 'upsertOne',
value: function upsertOne(query, update) {
return this._mongoCollection.update(query, update, { upsert: true });
}
}, {
key: 'updateOne',
value: function updateOne(query, update) {
return this._mongoCollection.updateOne(query, update);
}
}, {
key: 'updateMany',
value: function updateMany(query, update) {
return this._mongoCollection.updateMany(query, update);
}
}, {
key: 'deleteOne',
value: function deleteOne(query) {
return this._mongoCollection.deleteOne(query);
}
}, {
key: 'deleteMany',
value: function deleteMany(query) {
return this._mongoCollection.deleteMany(query);
}
}, {
key: '_ensureSparseUniqueIndexInBackground',
value: function _ensureSparseUniqueIndexInBackground(indexRequest) {
var _this2 = this;
return new Promise(function (resolve, reject) {
_this2._mongoCollection.ensureIndex(indexRequest, { unique: true, background: true, sparse: true }, function (error) {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
}, {
key: 'drop',
value: function drop() {
return this._mongoCollection.drop();
}
}]);
return MongoCollection;
}();
exports.default = MongoCollection;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | 1 6 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _MongoCollection = require('./MongoCollection');
var _MongoCollection2 = _interopRequireDefault(_MongoCollection);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function mongoFieldToParseSchemaField(type) {
if (type[0] === '*') {
return {
type: 'Pointer',
targetClass: type.slice(1)
};
}
if (type.startsWith('relation<')) {
return {
type: 'Relation',
targetClass: type.slice('relation<'.length, type.length - 1)
};
}
switch (type) {
case 'number':
return { type: 'Number' };
case 'string':
return { type: 'String' };
case 'boolean':
return { type: 'Boolean' };
case 'date':
return { type: 'Date' };
case 'map':
case 'object':
return { type: 'Object' };
case 'array':
return { type: 'Array' };
case 'geopoint':
return { type: 'GeoPoint' };
case 'file':
return { type: 'File' };
case 'bytes':
return { type: 'Bytes' };
}
}
var nonFieldSchemaKeys = ['_id', '_metadata', '_client_permissions'];
function mongoSchemaFieldsToParseSchemaFields(schema) {
var fieldNames = Object.keys(schema).filter(function (key) {
return nonFieldSchemaKeys.indexOf(key) === -1;
});
var response = fieldNames.reduce(function (obj, fieldName) {
obj[fieldName] = mongoFieldToParseSchemaField(schema[fieldName]);
return obj;
}, {});
response.ACL = { type: 'ACL' };
response.createdAt = { type: 'Date' };
response.updatedAt = { type: 'Date' };
response.objectId = { type: 'String' };
return response;
}
var emptyCLPS = Object.freeze({
find: {},
get: {},
create: {},
update: {},
delete: {},
addField: {}
});
var defaultCLPS = Object.freeze({
find: { '*': true },
get: { '*': true },
create: { '*': true },
update: { '*': true },
delete: { '*': true },
addField: { '*': true }
});
function mongoSchemaToParseSchema(mongoSchema) {
var clps = defaultCLPS;
if (mongoSchema._metadata && mongoSchema._metadata.class_permissions) {
clps = _extends({}, emptyCLPS, mongoSchema._metadata.class_permissions);
}
return {
className: mongoSchema._id,
fields: mongoSchemaFieldsToParseSchemaFields(mongoSchema),
classLevelPermissions: clps
};
}
function _mongoSchemaQueryFromNameQuery(name, query) {
var object = { _id: name };
if (query) {
Object.keys(query).forEach(function (key) {
object[key] = query[key];
});
}
return object;
}
// Returns a type suitable for inserting into mongo _SCHEMA collection.
// Does no validation. That is expected to be done in Parse Server.
function parseFieldTypeToMongoFieldType(_ref) {
var type = _ref.type,
targetClass = _ref.targetClass;
switch (type) {
case 'Pointer':
return '*' + targetClass;
case 'Relation':
return 'relation<' + targetClass + '>';
case 'Number':
return 'number';
case 'String':
return 'string';
case 'Boolean':
return 'boolean';
case 'Date':
return 'date';
case 'Object':
return 'object';
case 'Array':
return 'array';
case 'GeoPoint':
return 'geopoint';
case 'File':
return 'file';
}
}
var MongoSchemaCollection = function () {
function MongoSchemaCollection(collection) {
_classCallCheck(this, MongoSchemaCollection);
this._collection = collection;
}
_createClass(MongoSchemaCollection, [{
key: '_fetchAllSchemasFrom_SCHEMA',
value: function _fetchAllSchemasFrom_SCHEMA() {
return this._collection._rawFind({}).then(function (schemas) {
return schemas.map(mongoSchemaToParseSchema);
});
}
}, {
key: '_fechOneSchemaFrom_SCHEMA',
value: function _fechOneSchemaFrom_SCHEMA(name) {
return this._collection._rawFind(_mongoSchemaQueryFromNameQuery(name), { limit: 1 }).then(function (results) {
if (results.length === 1) {
return mongoSchemaToParseSchema(results[0]);
} else {
throw undefined;
}
});
}
// Atomically find and delete an object based on query.
}, {
key: 'findAndDeleteSchema',
value: function findAndDeleteSchema(name) {
return this._collection._mongoCollection.findAndRemove(_mongoSchemaQueryFromNameQuery(name), []);
}
}, {
key: 'updateSchema',
value: function updateSchema(name, update) {
return this._collection.updateOne(_mongoSchemaQueryFromNameQuery(name), update);
}
}, {
key: 'upsertSchema',
value: function upsertSchema(name, query, update) {
return this._collection.upsertOne(_mongoSchemaQueryFromNameQuery(name, query), update);
}
// Add a field to the schema. If database does not support the field
// type (e.g. mongo doesn't support more than one GeoPoint in a class) reject with an "Incorrect Type"
// Parse error with a desciptive message. If the field already exists, this function must
// not modify the schema, and must reject with DUPLICATE_VALUE error.
// If this is called for a class that doesn't exist, this function must create that class.
// TODO: throw an error if an unsupported field type is passed. Deciding whether a type is supported
// should be the job of the adapter. Some adapters may not support GeoPoint at all. Others may
// Support additional types that Mongo doesn't, like Money, or something.
// TODO: don't spend an extra query on finding the schema if the type we are trying to add isn't a GeoPoint.
}, {
key: 'addFieldIfNotExists',
value: function addFieldIfNotExists(className, fieldName, type) {
var _this = this;
return this._fechOneSchemaFrom_SCHEMA(className).then(function (schema) {
// The schema exists. Check for existing GeoPoints.
if (type.type === 'GeoPoint') {
// Make sure there are not other geopoint fields
if (Object.keys(schema.fields).some(function (existingField) {
return schema.fields[existingField].type === 'GeoPoint';
})) {
throw new _node2.default.Error(_node2.default.Error.INCORRECT_TYPE, 'MongoDB only supports one GeoPoint field in a class.');
}
}
return;
}, function (error) {
// If error is undefined, the schema doesn't exist, and we can create the schema with the field.
// If some other error, reject with it.
if (error === undefined) {
return;
}
throw error;
}).then(function () {
// We use $exists and $set to avoid overwriting the field type if it
// already exists. (it could have added inbetween the last query and the update)
return _this.upsertSchema(className, _defineProperty({}, fieldName, { '$exists': false }), { '$set': _defineProperty({}, fieldName, parseFieldTypeToMongoFieldType(type)) });
});
}
}]);
return MongoSchemaCollection;
}();
// Exported for testing reasons and because we haven't moved all mongo schema format
// related logic into the database adapter yet.
MongoSchemaCollection._TESTmongoSchemaToParseSchema = mongoSchemaToParseSchema;
MongoSchemaCollection.parseFieldTypeToMongoFieldType = parseFieldTypeToMongoFieldType;
exports.default = MongoSchemaCollection;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 | 1 1 23 1 1 1 1 1 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MongoStorageAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _MongoCollection = require('./MongoCollection');
var _MongoCollection2 = _interopRequireDefault(_MongoCollection);
var _MongoSchemaCollection = require('./MongoSchemaCollection');
var _MongoSchemaCollection2 = _interopRequireDefault(_MongoSchemaCollection);
var _mongodbUrl = require('../../../vendor/mongodbUrl');
var _MongoTransform = require('./MongoTransform');
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _defaults = require('../../../defaults');
var _defaults2 = _interopRequireDefault(_defaults);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var MongoSchemaCollectionName = '_SCHEMA';
var storageAdapterAllCollections = function storageAdapterAllCollections(mongoAdapter) {
return mongoAdapter.connect().then(function () {
return mongoAdapter.database.collections();
}).then(function (collections) {
return collections.filter(function (collection) {
if (collection.namespace.match(/\.system\./)) {
return false;
}
// TODO: If you have one app with a collection prefix that happens to be a prefix of another
// apps prefix, this will go very very badly. We should fix that somehow.
return collection.collectionName.indexOf(mongoAdapter._collectionPrefix) == 0;
});
});
};
var convertParseSchemaToMongoSchema = function convertParseSchemaToMongoSchema(_ref) {
var schema = _objectWithoutProperties(_ref, []);
delete schema.fields._rperm;
delete schema.fields._wperm;
if (schema.className === '_User') {
// Legacy mongo adapter knows about the difference between password and _hashed_password.
// Future database adapters will only know about _hashed_password.
// Note: Parse Server will bring back password with injectDefaultSchema, so we don't need
// to add _hashed_password back ever.
delete schema.fields._hashed_password;
}
return schema;
};
// Returns { code, error } if invalid, or { result }, an object
// suitable for inserting into _SCHEMA collection, otherwise.
var mongoSchemaFromFieldsAndClassNameAndCLP = function mongoSchemaFromFieldsAndClassNameAndCLP(fields, className, classLevelPermissions) {
var mongoObject = {
_id: className,
objectId: 'string',
updatedAt: 'string',
createdAt: 'string'
};
for (var fieldName in fields) {
mongoObject[fieldName] = _MongoSchemaCollection2.default.parseFieldTypeToMongoFieldType(fields[fieldName]);
}
if (typeof classLevelPermissions !== 'undefined') {
mongoObject._metadata = mongoObject._metadata || {};
if (!classLevelPermissions) {
delete mongoObject._metadata.class_permissions;
} else {
mongoObject._metadata.class_permissions = classLevelPermissions;
}
}
return mongoObject;
};
var MongoStorageAdapter = exports.MongoStorageAdapter = function () {
// Public
function MongoStorageAdapter(_ref2) {
var _ref2$uri = _ref2.uri,
uri = _ref2$uri === undefined ? _defaults2.default.DefaultMongoURI : _ref2$uri,
_ref2$collectionPrefi = _ref2.collectionPrefix,
collectionPrefix = _ref2$collectionPrefi === undefined ? '' : _ref2$collectionPrefi,
_ref2$mongoOptions = _ref2.mongoOptions,
mongoOptions = _ref2$mongoOptions === undefined ? {} : _ref2$mongoOptions;
_classCallCheck(this, MongoStorageAdapter);
this._uri = uri;
this._collectionPrefix = collectionPrefix;
this._mongoOptions = mongoOptions;
// MaxTimeMS is not a global MongoDB client option, it is applied per operation.
this._maxTimeMS = mongoOptions.maxTimeMS;
process.on('SIGTERM', this.handleShutdown(this));
process.on('SIGINT', this.handleShutdown(this));
}
// Private
_createClass(MongoStorageAdapter, [{
key: 'handleShutdown',
value: function handleShutdown(storageAdapter) {
return function () {
if (!storageAdapter.database) {
return;
}
storageAdapter.database.close(false);
};
}
}, {
key: 'connect',
value: function connect() {
var _this = this;
if (this.connectionPromise) {
return this.connectionPromise;
}
// parsing and re-formatting causes the auth value (if there) to get URI
// encoded
var encodedUri = (0, _mongodbUrl.format)((0, _mongodbUrl.parse)(this._uri));
this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions).then(function (database) {
if (!database) {
delete _this.connectionPromise;
return;
}
database.on('error', function () {
delete _this.connectionPromise;
});
database.on('close', function () {
delete _this.connectionPromise;
});
_this.database = database;
}).catch(function (err) {
delete _this.connectionPromise;
return Promise.reject(err);
});
return this.connectionPromise;
}
}, {
key: '_adaptiveCollection',
value: function _adaptiveCollection(name) {
var _this2 = this;
return this.connect().then(function () {
return _this2.database.collection(_this2._collectionPrefix + name);
}).then(function (rawCollection) {
return new _MongoCollection2.default(rawCollection);
});
}
}, {
key: '_schemaCollection',
value: function _schemaCollection() {
var _this3 = this;
return this.connect().then(function () {
return _this3._adaptiveCollection(MongoSchemaCollectionName);
}).then(function (collection) {
return new _MongoSchemaCollection2.default(collection);
});
}
}, {
key: 'classExists',
value: function classExists(name) {
var _this4 = this;
return this.connect().then(function () {
return _this4.database.listCollections({ name: _this4._collectionPrefix + name }).toArray();
}).then(function (collections) {
return collections.length > 0;
});
}
}, {
key: 'setClassLevelPermissions',
value: function setClassLevelPermissions(className, CLPs) {
return this._schemaCollection().then(function (schemaCollection) {
return schemaCollection.updateSchema(className, {
$set: { _metadata: { class_permissions: CLPs } }
});
});
}
}, {
key: 'createClass',
value: function createClass(className, schema) {
schema = convertParseSchemaToMongoSchema(schema);
var mongoObject = mongoSchemaFromFieldsAndClassNameAndCLP(schema.fields, className, schema.classLevelPermissions);
mongoObject._id = className;
return this._schemaCollection().then(function (schemaCollection) {
return schemaCollection._collection.insertOne(mongoObject);
}).then(function (result) {
return _MongoSchemaCollection2.default._TESTmongoSchemaToParseSchema(result.ops[0]);
}).catch(function (error) {
if (error.code === 11000) {
//Mongo's duplicate key error
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'Class already exists.');
} else {
throw error;
}
});
}
}, {
key: 'addFieldIfNotExists',
value: function addFieldIfNotExists(className, fieldName, type) {
return this._schemaCollection().then(function (schemaCollection) {
return schemaCollection.addFieldIfNotExists(className, fieldName, type);
});
}
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
// and resolves with false if it wasn't (eg. a join table). Rejects if deletion was impossible.
}, {
key: 'deleteClass',
value: function deleteClass(className) {
var _this5 = this;
return this._adaptiveCollection(className).then(function (collection) {
return collection.drop();
}).catch(function (error) {
// 'ns not found' means collection was already gone. Ignore deletion attempt.
if (error.message == 'ns not found') {
return;
}
throw error;
})
// We've dropped the collection, now remove the _SCHEMA document
.then(function () {
return _this5._schemaCollection();
}).then(function (schemaCollection) {
return schemaCollection.findAndDeleteSchema(className);
});
}
// Delete all data known to this adatper. Used for testing.
}, {
key: 'deleteAllClasses',
value: function deleteAllClasses() {
return storageAdapterAllCollections(this).then(function (collections) {
return Promise.all(collections.map(function (collection) {
return collection.drop();
}));
});
}
// Remove the column and all the data. For Relations, the _Join collection is handled
// specially, this function does not delete _Join columns. It should, however, indicate
// that the relation fields does not exist anymore. In mongo, this means removing it from
// the _SCHEMA collection. There should be no actual data in the collection under the same name
// as the relation column, so it's fine to attempt to delete it. If the fields listed to be
// deleted do not exist, this function should return successfully anyways. Checking for
// attempts to delete non-existent fields is the responsibility of Parse Server.
// Pointer field names are passed for legacy reasons: the original mongo
// format stored pointer field names differently in the database, and therefore
// needed to know the type of the field before it could delete it. Future database
// adatpers should ignore the pointerFieldNames argument. All the field names are in
// fieldNames, they show up additionally in the pointerFieldNames database for use
// by the mongo adapter, which deals with the legacy mongo format.
// This function is not obligated to delete fields atomically. It is given the field
// names in a list so that databases that are capable of deleting fields atomically
// may do so.
// Returns a Promise.
}, {
key: 'deleteFields',
value: function deleteFields(className, schema, fieldNames) {
var _this6 = this;
var mongoFormatNames = fieldNames.map(function (fieldName) {
if (schema.fields[fieldName].type === 'Pointer') {
return '_p_' + fieldName;
} else {
return fieldName;
}
});
var collectionUpdate = { '$unset': {} };
mongoFormatNames.forEach(function (name) {
collectionUpdate['$unset'][name] = null;
});
var schemaUpdate = { '$unset': {} };
fieldNames.forEach(function (name) {
schemaUpdate['$unset'][name] = null;
});
return this._adaptiveCollection(className).then(function (collection) {
return collection.updateMany({}, collectionUpdate);
}).then(function () {
return _this6._schemaCollection();
}).then(function (schemaCollection) {
return schemaCollection.updateSchema(className, schemaUpdate);
});
}
// Return a promise for all schemas known to this adapter, in Parse format. In case the
// schemas cannot be retrieved, returns a promise that rejects. Requirements for the
// rejection reason are TBD.
}, {
key: 'getAllClasses',
value: function getAllClasses() {
return this._schemaCollection().then(function (schemasCollection) {
return schemasCollection._fetchAllSchemasFrom_SCHEMA();
});
}
// Return a promise for the schema with the given name, in Parse format. If
// this adapter doesn't know about the schema, return a promise that rejects with
// undefined as the reason.
}, {
key: 'getClass',
value: function getClass(className) {
return this._schemaCollection().then(function (schemasCollection) {
return schemasCollection._fechOneSchemaFrom_SCHEMA(className);
});
}
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
// and should infer from the type. Or maybe does need the schema for validations. Or maybe needs
// the schem only for the legacy mongo format. We'll figure that out later.
}, {
key: 'createObject',
value: function createObject(className, schema, object) {
schema = convertParseSchemaToMongoSchema(schema);
var mongoObject = (0, _MongoTransform.parseObjectToMongoObjectForCreate)(className, object, schema);
return this._adaptiveCollection(className).then(function (collection) {
return collection.insertOne(mongoObject);
}).catch(function (error) {
if (error.code === 11000) {
// Duplicate value
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
}
throw error;
});
}
// Remove all objects that match the given Parse Query.
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
}, {
key: 'deleteObjectsByQuery',
value: function deleteObjectsByQuery(className, schema, query) {
schema = convertParseSchemaToMongoSchema(schema);
return this._adaptiveCollection(className).then(function (collection) {
var mongoWhere = (0, _MongoTransform.transformWhere)(className, query, schema);
return collection.deleteMany(mongoWhere);
}).then(function (_ref3) {
var result = _ref3.result;
if (result.n === 0) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Object not found.');
}
return Promise.resolve();
}, function () {
throw new _node2.default.Error(_node2.default.Error.INTERNAL_SERVER_ERROR, 'Database adapter error');
});
}
// Apply the update to all objects that match the given Parse Query.
}, {
key: 'updateObjectsByQuery',
value: function updateObjectsByQuery(className, schema, query, update) {
schema = convertParseSchemaToMongoSchema(schema);
var mongoUpdate = (0, _MongoTransform.transformUpdate)(className, update, schema);
var mongoWhere = (0, _MongoTransform.transformWhere)(className, query, schema);
return this._adaptiveCollection(className).then(function (collection) {
return collection.updateMany(mongoWhere, mongoUpdate);
});
}
// Atomically finds and updates an object based on query.
// Return value not currently well specified.
}, {
key: 'findOneAndUpdate',
value: function findOneAndUpdate(className, schema, query, update) {
schema = convertParseSchemaToMongoSchema(schema);
var mongoUpdate = (0, _MongoTransform.transformUpdate)(className, update, schema);
var mongoWhere = (0, _MongoTransform.transformWhere)(className, query, schema);
return this._adaptiveCollection(className).then(function (collection) {
return collection._mongoCollection.findAndModify(mongoWhere, [], mongoUpdate, { new: true });
}).then(function (result) {
return (0, _MongoTransform.mongoObjectToParseObject)(className, result.value, schema);
});
}
// Hopefully we can get rid of this. It's only used for config and hooks.
}, {
key: 'upsertOneObject',
value: function upsertOneObject(className, schema, query, update) {
schema = convertParseSchemaToMongoSchema(schema);
var mongoUpdate = (0, _MongoTransform.transformUpdate)(className, update, schema);
var mongoWhere = (0, _MongoTransform.transformWhere)(className, query, schema);
return this._adaptiveCollection(className).then(function (collection) {
return collection.upsertOne(mongoWhere, mongoUpdate);
});
}
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
}, {
key: 'find',
value: function find(className, schema, query, _ref4) {
var _this7 = this;
var skip = _ref4.skip,
limit = _ref4.limit,
sort = _ref4.sort,
keys = _ref4.keys;
schema = convertParseSchemaToMongoSchema(schema);
var mongoWhere = (0, _MongoTransform.transformWhere)(className, query, schema);
var mongoSort = _lodash2.default.mapKeys(sort, function (value, fieldName) {
return (0, _MongoTransform.transformKey)(className, fieldName, schema);
});
var mongoKeys = _lodash2.default.reduce(keys, function (memo, key) {
memo[(0, _MongoTransform.transformKey)(className, key, schema)] = 1;
return memo;
}, {});
return this._adaptiveCollection(className).then(function (collection) {
return collection.find(mongoWhere, {
skip: skip,
limit: limit,
sort: mongoSort,
keys: mongoKeys,
maxTimeMS: _this7._maxTimeMS
});
}).then(function (objects) {
return objects.map(function (object) {
return (0, _MongoTransform.mongoObjectToParseObject)(className, object, schema);
});
});
}
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
// currently know which fields are nullable and which aren't, we ignore that criteria.
// As such, we shouldn't expose this function to users of parse until we have an out-of-band
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
// which is why we use sparse indexes.
}, {
key: 'ensureUniqueness',
value: function ensureUniqueness(className, schema, fieldNames) {
schema = convertParseSchemaToMongoSchema(schema);
var indexCreationRequest = {};
var mongoFieldNames = fieldNames.map(function (fieldName) {
return (0, _MongoTransform.transformKey)(className, fieldName, schema);
});
mongoFieldNames.forEach(function (fieldName) {
indexCreationRequest[fieldName] = 1;
});
return this._adaptiveCollection(className).then(function (collection) {
return collection._ensureSparseUniqueIndexInBackground(indexCreationRequest);
}).catch(function (error) {
if (error.code === 11000) {
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'Tried to ensure field uniqueness for a class that already has duplicates.');
} else {
throw error;
}
});
}
// Used in tests
}, {
key: '_rawFind',
value: function _rawFind(className, query) {
var _this8 = this;
return this._adaptiveCollection(className).then(function (collection) {
return collection.find(query, {
maxTimeMS: _this8._maxTimeMS
});
});
}
// Executes a count.
}, {
key: 'count',
value: function count(className, schema, query) {
var _this9 = this;
schema = convertParseSchemaToMongoSchema(schema);
return this._adaptiveCollection(className).then(function (collection) {
return collection.count((0, _MongoTransform.transformWhere)(className, query, schema), {
maxTimeMS: _this9._maxTimeMS
});
});
}
}, {
key: 'performInitialization',
value: function performInitialization() {
return Promise.resolve();
}
}]);
return MongoStorageAdapter;
}();
exports.default = MongoStorageAdapter;
module.exports = MongoStorageAdapter; // Required for tests
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _logger = require('../../../logger'); var _logger2 = _interopRequireDefault(_logger); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var mongodb = require('mongodb'); var Parse = require('parse/node').Parse; var transformKey = function transformKey(className, fieldName, schema) { // Check if the schema is known since it's a built-in field. switch (fieldName) { case 'objectId': return '_id'; case 'createdAt': return '_created_at'; case 'updatedAt': return '_updated_at'; case 'sessionToken': return '_session_token'; } if (schema.fields[fieldName] && schema.fields[fieldName].__type == 'Pointer') { fieldName = '_p_' + fieldName; } else if (schema.fields[fieldName] && schema.fields[fieldName].type == 'Pointer') { fieldName = '_p_' + fieldName; } return fieldName; }; var transformKeyValueForUpdate = function transformKeyValueForUpdate(className, restKey, restValue, parseFormatSchema) { // Check if the schema is known since it's a built-in field. var key = restKey; var timeField = false; switch (key) { case 'objectId': case '_id': if (className === '_GlobalConfig') { return { key: key, value: parseInt(restValue) }; } key = '_id'; break; case 'createdAt': case '_created_at': key = '_created_at'; timeField = true; break; case 'updatedAt': case '_updated_at': key = '_updated_at'; timeField = true; break; case 'sessionToken': case '_session_token': key = '_session_token'; break; case 'expiresAt': case '_expiresAt': key = 'expiresAt'; timeField = true; break; case '_email_verify_token_expires_at': key = '_email_verify_token_expires_at'; timeField = true; break; case '_account_lockout_expires_at': key = '_account_lockout_expires_at'; timeField = true; break; case '_failed_login_count': key = '_failed_login_count'; break; case '_perishable_token_expires_at': key = '_perishable_token_expires_at'; timeField = true; break; case '_password_changed_at': key = '_password_changed_at'; timeField = true; break; case '_rperm': case '_wperm': return { key: key, value: restValue }; } if (parseFormatSchema.fields[key] && parseFormatSchema.fields[key].type === 'Pointer' || !parseFormatSchema.fields[key] && restValue && restValue.__type == 'Pointer') { key = '_p_' + key; } // Handle atomic values var value = transformTopLevelAtom(restValue); if (value !== CannotTransform) { if (timeField && typeof value === 'string') { value = new Date(value); } if (restKey.indexOf('.') > 0) { return { key: key, value: restValue }; } return { key: key, value: value }; } // Handle arrays if (restValue instanceof Array) { value = restValue.map(transformInteriorValue); return { key: key, value: value }; } // Handle update operators if ((typeof restValue === 'undefined' ? 'undefined' : _typeof(restValue)) === 'object' && '__op' in restValue) { return { key: key, value: transformUpdateOperator(restValue, false) }; } // Handle normal objects by recursing value = _lodash2.default.mapValues(restValue, transformInteriorValue); return { key: key, value: value }; }; var transformInteriorValue = function transformInteriorValue(restValue) { if (restValue !== null && (typeof restValue === 'undefined' ? 'undefined' : _typeof(restValue)) === 'object' && Object.keys(restValue).some(function (key) { return key.includes('$') || key.includes('.'); })) { throw new Parse.Error(Parse.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters"); } // Handle atomic values var value = transformInteriorAtom(restValue); if (value !== CannotTransform) { return value; } // Handle arrays if (restValue instanceof Array) { return restValue.map(transformInteriorValue); } // Handle update operators if ((typeof restValue === 'undefined' ? 'undefined' : _typeof(restValue)) === 'object' && '__op' in restValue) { return transformUpdateOperator(restValue, true); } // Handle normal objects by recursing return _lodash2.default.mapValues(restValue, transformInteriorValue); }; var valueAsDate = function valueAsDate(value) { if (typeof value === 'string') { return new Date(value); } else if (value instanceof Date) { return value; } return false; }; function transformQueryKeyValue(className, key, value, schema) { switch (key) { case 'createdAt': if (valueAsDate(value)) { return { key: '_created_at', value: valueAsDate(value) }; } key = '_created_at'; break; case 'updatedAt': if (valueAsDate(value)) { return { key: '_updated_at', value: valueAsDate(value) }; } key = '_updated_at'; break; case 'expiresAt': if (valueAsDate(value)) { return { key: 'expiresAt', value: valueAsDate(value) }; } break; case '_email_verify_token_expires_at': if (valueAsDate(value)) { return { key: '_email_verify_token_expires_at', value: valueAsDate(value) }; } break; case 'objectId': { if (className === '_GlobalConfig') { value = parseInt(value); } return { key: '_id', value: value }; } case '_account_lockout_expires_at': if (valueAsDate(value)) { return { key: '_account_lockout_expires_at', value: valueAsDate(value) }; } break; case '_failed_login_count': return { key: key, value: value }; case 'sessionToken': return { key: '_session_token', value: value }; case '_perishable_token_expires_at': if (valueAsDate(value)) { return { key: '_perishable_token_expires_at', value: valueAsDate(value) }; } break; case '_password_changed_at': if (valueAsDate(value)) { return { key: '_password_changed_at', value: valueAsDate(value) }; } break; case '_rperm': case '_wperm': case '_perishable_token': case '_email_verify_token': return { key: key, value: value }; case '$or': return { key: '$or', value: value.map(function (subQuery) { return transformWhere(className, subQuery, schema); }) }; case '$and': return { key: '$and', value: value.map(function (subQuery) { return transformWhere(className, subQuery, schema); }) }; default: { // Other auth data var authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/); if (authDataMatch) { var provider = authDataMatch[1]; // Special-case auth data. return { key: '_auth_data_' + provider + '.id', value: value }; } } } var expectedTypeIsArray = schema && schema.fields[key] && schema.fields[key].type === 'Array'; var expectedTypeIsPointer = schema && schema.fields[key] && schema.fields[key].type === 'Pointer'; if (expectedTypeIsPointer || !schema && value && value.__type === 'Pointer') { key = '_p_' + key; } // Handle query constraints var transformedConstraint = transformConstraint(value, expectedTypeIsArray); if (transformedConstraint !== CannotTransform) { return { key: key, value: transformedConstraint }; } if (expectedTypeIsArray && !(value instanceof Array)) { return { key: key, value: { '$all': [value] } }; } // Handle atomic values if (transformTopLevelAtom(value) !== CannotTransform) { return { key: key, value: transformTopLevelAtom(value) }; } else { throw new Parse.Error(Parse.Error.INVALID_JSON, 'You cannot use ' + value + ' as a query parameter.'); } } // Main exposed method to help run queries. // restWhere is the "where" clause in REST API form. // Returns the mongo form of the query. function transformWhere(className, restWhere, schema) { var mongoWhere = {}; for (var restKey in restWhere) { var out = transformQueryKeyValue(className, restKey, restWhere[restKey], schema); mongoWhere[out.key] = out.value; } return mongoWhere; } var parseObjectKeyValueToMongoObjectKeyValue = function parseObjectKeyValueToMongoObjectKeyValue(restKey, restValue, schema) { // Check if the schema is known since it's a built-in field. var transformedValue = void 0; var coercedToDate = void 0; switch (restKey) { case 'objectId': return { key: '_id', value: restValue }; case 'expiresAt': transformedValue = transformTopLevelAtom(restValue); coercedToDate = typeof transformedValue === 'string' ? new Date(transformedValue) : transformedValue; return { key: 'expiresAt', value: coercedToDate }; case '_email_verify_token_expires_at': transformedValue = transformTopLevelAtom(restValue); coercedToDate = typeof transformedValue === 'string' ? new Date(transformedValue) : transformedValue; return { key: '_email_verify_token_expires_at', value: coercedToDate }; case '_account_lockout_expires_at': transformedValue = transformTopLevelAtom(restValue); coercedToDate = typeof transformedValue === 'string' ? new Date(transformedValue) : transformedValue; return { key: '_account_lockout_expires_at', value: coercedToDate }; case '_perishable_token_expires_at': transformedValue = transformTopLevelAtom(restValue); coercedToDate = typeof transformedValue === 'string' ? new Date(transformedValue) : transformedValue; return { key: '_perishable_token_expires_at', value: coercedToDate }; case '_password_changed_at': transformedValue = transformTopLevelAtom(restValue); coercedToDate = typeof transformedValue === 'string' ? new Date(transformedValue) : transformedValue; return { key: '_password_changed_at', value: coercedToDate }; case '_failed_login_count': case '_rperm': case '_wperm': case '_email_verify_token': case '_hashed_password': case '_perishable_token': return { key: restKey, value: restValue }; case 'sessionToken': return { key: '_session_token', value: restValue }; default: // Auth data should have been transformed already if (restKey.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) { throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'can only query on ' + restKey); } // Trust that the auth data has been transformed and save it directly if (restKey.match(/^_auth_data_[a-zA-Z0-9_]+$/)) { return { key: restKey, value: restValue }; } } //skip straight to transformTopLevelAtom for Bytes, they don't show up in the schema for some reason if (restValue && restValue.__type !== 'Bytes') { //Note: We may not know the type of a field here, as the user could be saving (null) to a field //That never existed before, meaning we can't infer the type. if (schema.fields[restKey] && schema.fields[restKey].type == 'Pointer' || restValue.__type == 'Pointer') { restKey = '_p_' + restKey; } } // Handle atomic values var value = transformTopLevelAtom(restValue); if (value !== CannotTransform) { return { key: restKey, value: value }; } // ACLs are handled before this method is called // If an ACL key still exists here, something is wrong. if (restKey === 'ACL') { throw 'There was a problem transforming an ACL.'; } // Handle arrays if (restValue instanceof Array) { value = restValue.map(transformInteriorValue); return { key: restKey, value: value }; } // Handle normal objects by recursing if (Object.keys(restValue).some(function (key) { return key.includes('$') || key.includes('.'); })) { throw new Parse.Error(Parse.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters"); } value = _lodash2.default.mapValues(restValue, transformInteriorValue); return { key: restKey, value: value }; }; var parseObjectToMongoObjectForCreate = function parseObjectToMongoObjectForCreate(className, restCreate, schema) { restCreate = addLegacyACL(restCreate); var mongoCreate = {}; for (var restKey in restCreate) { if (restCreate[restKey] && restCreate[restKey].__type === 'Relation') { continue; } var _parseObjectKeyValueT = parseObjectKeyValueToMongoObjectKeyValue(restKey, restCreate[restKey], schema), key = _parseObjectKeyValueT.key, value = _parseObjectKeyValueT.value; if (value !== undefined) { mongoCreate[key] = value; } } // Use the legacy mongo format for createdAt and updatedAt if (mongoCreate.createdAt) { mongoCreate._created_at = new Date(mongoCreate.createdAt.iso || mongoCreate.createdAt); delete mongoCreate.createdAt; } if (mongoCreate.updatedAt) { mongoCreate._updated_at = new Date(mongoCreate.updatedAt.iso || mongoCreate.updatedAt); delete mongoCreate.updatedAt; } return mongoCreate; }; // Main exposed method to help update old objects. var transformUpdate = function transformUpdate(className, restUpdate, parseFormatSchema) { var mongoUpdate = {}; var acl = addLegacyACL(restUpdate); if (acl._rperm || acl._wperm || acl._acl) { mongoUpdate.$set = {}; if (acl._rperm) { mongoUpdate.$set._rperm = acl._rperm; } if (acl._wperm) { mongoUpdate.$set._wperm = acl._wperm; } if (acl._acl) { mongoUpdate.$set._acl = acl._acl; } } for (var restKey in restUpdate) { if (restUpdate[restKey] && restUpdate[restKey].__type === 'Relation') { continue; } var out = transformKeyValueForUpdate(className, restKey, restUpdate[restKey], parseFormatSchema); // If the output value is an object with any $ keys, it's an // operator that needs to be lifted onto the top level update // object. if (_typeof(out.value) === 'object' && out.value !== null && out.value.__op) { mongoUpdate[out.value.__op] = mongoUpdate[out.value.__op] || {}; mongoUpdate[out.value.__op][out.key] = out.value.arg; } else { mongoUpdate['$set'] = mongoUpdate['$set'] || {}; mongoUpdate['$set'][out.key] = out.value; } } return mongoUpdate; }; // Add the legacy _acl format. var addLegacyACL = function addLegacyACL(restObject) { var restObjectCopy = _extends({}, restObject); var _acl = {}; if (restObject._wperm) { restObject._wperm.forEach(function (entry) { _acl[entry] = { w: true }; }); restObjectCopy._acl = _acl; } if (restObject._rperm) { restObject._rperm.forEach(function (entry) { if (!(entry in _acl)) { _acl[entry] = { r: true }; } else { _acl[entry].r = true; } }); restObjectCopy._acl = _acl; } return restObjectCopy; }; // A sentinel value that helper transformations return when they // cannot perform a transformation function CannotTransform() {} var transformInteriorAtom = function transformInteriorAtom(atom) { // TODO: check validity harder for the __type-defined types if ((typeof atom === 'undefined' ? 'undefined' : _typeof(atom)) === 'object' && atom && !(atom instanceof Date) && atom.__type === 'Pointer') { return { __type: 'Pointer', className: atom.className, objectId: atom.objectId }; } else if (typeof atom === 'function' || (typeof atom === 'undefined' ? 'undefined' : _typeof(atom)) === 'symbol') { throw new Parse.Error(Parse.Error.INVALID_JSON, 'cannot transform value: ' + atom); } else if (DateCoder.isValidJSON(atom)) { return DateCoder.JSONToDatabase(atom); } else if (BytesCoder.isValidJSON(atom)) { return BytesCoder.JSONToDatabase(atom); } else { return atom; } }; // Helper function to transform an atom from REST format to Mongo format. // An atom is anything that can't contain other expressions. So it // includes things where objects are used to represent other // datatypes, like pointers and dates, but it does not include objects // or arrays with generic stuff inside. // Raises an error if this cannot possibly be valid REST format. // Returns CannotTransform if it's just not an atom function transformTopLevelAtom(atom) { switch (typeof atom === 'undefined' ? 'undefined' : _typeof(atom)) { case 'string': case 'number': case 'boolean': return atom; case 'undefined': return atom; case 'symbol': case 'function': throw new Parse.Error(Parse.Error.INVALID_JSON, 'cannot transform value: ' + atom); case 'object': if (atom instanceof Date) { // Technically dates are not rest format, but, it seems pretty // clear what they should be transformed to, so let's just do it. return atom; } if (atom === null) { return atom; } // TODO: check validity harder for the __type-defined types if (atom.__type == 'Pointer') { return atom.className + '$' + atom.objectId; } if (DateCoder.isValidJSON(atom)) { return DateCoder.JSONToDatabase(atom); } if (BytesCoder.isValidJSON(atom)) { return BytesCoder.JSONToDatabase(atom); } if (GeoPointCoder.isValidJSON(atom)) { return GeoPointCoder.JSONToDatabase(atom); } if (FileCoder.isValidJSON(atom)) { return FileCoder.JSONToDatabase(atom); } return CannotTransform; default: // I don't think typeof can ever let us get here throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'really did not expect value: ' + atom); } } // Transforms a query constraint from REST API format to Mongo format. // A constraint is something with fields like $lt. // If it is not a valid constraint but it could be a valid something // else, return CannotTransform. // inArray is whether this is an array field. function transformConstraint(constraint, inArray) { if ((typeof constraint === 'undefined' ? 'undefined' : _typeof(constraint)) !== 'object' || !constraint) { return CannotTransform; } var transformFunction = inArray ? transformInteriorAtom : transformTopLevelAtom; var transformer = function transformer(atom) { var result = transformFunction(atom); if (result === CannotTransform) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad atom: ' + JSON.stringify(atom)); } return result; }; // keys is the constraints in reverse alphabetical order. // This is a hack so that: // $regex is handled before $options // $nearSphere is handled before $maxDistance var keys = Object.keys(constraint).sort().reverse(); var answer = {}; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var key = _step.value; switch (key) { case '$lt': case '$lte': case '$gt': case '$gte': case '$exists': case '$ne': case '$eq': answer[key] = transformer(constraint[key]); break; case '$in': case '$nin': { var arr = constraint[key]; if (!(arr instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad ' + key + ' value'); } answer[key] = _lodash2.default.flatMap(arr, function (value) { return function (atom) { if (Array.isArray(atom)) { return value.map(transformer); } else { return transformer(atom); } }(value); }); break; } case '$all': { var _arr = constraint[key]; if (!(_arr instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad ' + key + ' value'); } answer[key] = _arr.map(transformInteriorAtom); break; } case '$regex': var s = constraint[key]; if (typeof s !== 'string') { throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad regex: ' + s); } answer[key] = s; break; case '$options': answer[key] = constraint[key]; break; case '$nearSphere': var point = constraint[key]; answer[key] = [point.longitude, point.latitude]; break; case '$maxDistance': answer[key] = constraint[key]; break; // The SDKs don't seem to use these but they are documented in the // REST API docs. case '$maxDistanceInRadians': answer['$maxDistance'] = constraint[key]; break; case '$maxDistanceInMiles': answer['$maxDistance'] = constraint[key] / 3959; break; case '$maxDistanceInKilometers': answer['$maxDistance'] = constraint[key] / 6371; break; case '$select': case '$dontSelect': throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, 'the ' + key + ' constraint is not supported yet'); case '$within': var box = constraint[key]['$box']; if (!box || box.length != 2) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'malformatted $within arg'); } answer[key] = { '$box': [[box[0].longitude, box[0].latitude], [box[1].longitude, box[1].latitude]] }; break; default: if (key.match(/^\$+/)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad constraint: ' + key); } return CannotTransform; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return answer; } // Transforms an update operator from REST format to mongo format. // To be transformed, the input should have an __op field. // If flatten is true, this will flatten operators to their static // data format. For example, an increment of 2 would simply become a // 2. // The output for a non-flattened operator is a hash with __op being // the mongo op, and arg being the argument. // The output for a flattened operator is just a value. // Returns undefined if this should be a no-op. function transformUpdateOperator(_ref, flatten) { var __op = _ref.__op, amount = _ref.amount, objects = _ref.objects; switch (__op) { case 'Delete': if (flatten) { return undefined; } else { return { __op: '$unset', arg: '' }; } case 'Increment': if (typeof amount !== 'number') { throw new Parse.Error(Parse.Error.INVALID_JSON, 'incrementing must provide a number'); } if (flatten) { return amount; } else { return { __op: '$inc', arg: amount }; } case 'Add': case 'AddUnique': if (!(objects instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array'); } var toAdd = objects.map(transformInteriorAtom); if (flatten) { return toAdd; } else { var mongoOp = { Add: '$push', AddUnique: '$addToSet' }[__op]; return { __op: mongoOp, arg: { '$each': toAdd } }; } case 'Remove': if (!(objects instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to remove must be an array'); } var toRemove = objects.map(transformInteriorAtom); if (flatten) { return []; } else { return { __op: '$pullAll', arg: toRemove }; } default: throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, 'The ' + __op + ' operator is not supported yet.'); } } var nestedMongoObjectToNestedParseObject = function nestedMongoObjectToNestedParseObject(mongoObject) { switch (typeof mongoObject === 'undefined' ? 'undefined' : _typeof(mongoObject)) { case 'string': case 'number': case 'boolean': return mongoObject; case 'undefined': case 'symbol': case 'function': throw 'bad value in mongoObjectToParseObject'; case 'object': if (mongoObject === null) { return null; } if (mongoObject instanceof Array) { return mongoObject.map(nestedMongoObjectToNestedParseObject); } if (mongoObject instanceof Date) { return Parse._encode(mongoObject); } if (mongoObject instanceof mongodb.Long) { return mongoObject.toNumber(); } if (mongoObject instanceof mongodb.Double) { return mongoObject.value; } if (BytesCoder.isValidDatabaseObject(mongoObject)) { return BytesCoder.databaseToJSON(mongoObject); } if (mongoObject.hasOwnProperty('__type') && mongoObject.__type == 'Date' && mongoObject.iso instanceof Date) { mongoObject.iso = mongoObject.iso.toJSON(); return mongoObject; } return _lodash2.default.mapValues(mongoObject, nestedMongoObjectToNestedParseObject); default: throw 'unknown js type'; } }; // Converts from a mongo-format object to a REST-format object. // Does not strip out anything based on a lack of authentication. var mongoObjectToParseObject = function mongoObjectToParseObject(className, mongoObject, schema) { switch (typeof mongoObject === 'undefined' ? 'undefined' : _typeof(mongoObject)) { case 'string': case 'number': case 'boolean': return mongoObject; case 'undefined': case 'symbol': case 'function': throw 'bad value in mongoObjectToParseObject'; case 'object': { if (mongoObject === null) { return null; } if (mongoObject instanceof Array) { return mongoObject.map(nestedMongoObjectToNestedParseObject); } if (mongoObject instanceof Date) { return Parse._encode(mongoObject); } if (mongoObject instanceof mongodb.Long) { return mongoObject.toNumber(); } if (mongoObject instanceof mongodb.Double) { return mongoObject.value; } if (BytesCoder.isValidDatabaseObject(mongoObject)) { return BytesCoder.databaseToJSON(mongoObject); } var restObject = {}; if (mongoObject._rperm || mongoObject._wperm) { restObject._rperm = mongoObject._rperm || []; restObject._wperm = mongoObject._wperm || []; delete mongoObject._rperm; delete mongoObject._wperm; } for (var key in mongoObject) { switch (key) { case '_id': restObject['objectId'] = '' + mongoObject[key]; break; case '_hashed_password': restObject._hashed_password = mongoObject[key]; break; case '_acl': break; case '_email_verify_token': case '_perishable_token': case '_perishable_token_expires_at': case '_password_changed_at': case '_tombstone': case '_email_verify_token_expires_at': case '_account_lockout_expires_at': case '_failed_login_count': case '_password_history': // Those keys will be deleted if needed in the DB Controller restObject[key] = mongoObject[key]; break; case '_session_token': restObject['sessionToken'] = mongoObject[key]; break; case 'updatedAt': case '_updated_at': restObject['updatedAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'createdAt': case '_created_at': restObject['createdAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'expiresAt': case '_expiresAt': restObject['expiresAt'] = Parse._encode(new Date(mongoObject[key])); break; default: // Check other auth data keys var authDataMatch = key.match(/^_auth_data_([a-zA-Z0-9_]+)$/); if (authDataMatch) { var provider = authDataMatch[1]; restObject['authData'] = restObject['authData'] || {}; restObject['authData'][provider] = mongoObject[key]; break; } if (key.indexOf('_p_') == 0) { var newKey = key.substring(3); if (!schema.fields[newKey]) { _logger2.default.info('transform.js', 'Found a pointer column not in the schema, dropping it.', className, newKey); break; } if (schema.fields[newKey].type !== 'Pointer') { _logger2.default.info('transform.js', 'Found a pointer in a non-pointer column, dropping it.', className, key); break; } if (mongoObject[key] === null) { break; } var objData = mongoObject[key].split('$'); if (objData[0] !== schema.fields[newKey].targetClass) { throw 'pointer to incorrect className'; } restObject[newKey] = { __type: 'Pointer', className: objData[0], objectId: objData[1] }; break; } else if (key[0] == '_' && key != '__type') { throw 'bad key in untransform: ' + key; } else { var value = mongoObject[key]; if (schema.fields[key] && schema.fields[key].type === 'File' && FileCoder.isValidDatabaseObject(value)) { restObject[key] = FileCoder.databaseToJSON(value); break; } if (schema.fields[key] && schema.fields[key].type === 'GeoPoint' && GeoPointCoder.isValidDatabaseObject(value)) { restObject[key] = GeoPointCoder.databaseToJSON(value); break; } if (schema.fields[key] && schema.fields[key].type === 'Bytes' && BytesCoder.isValidDatabaseObject(value)) { restObject[key] = BytesCoder.databaseToJSON(value); break; } } restObject[key] = nestedMongoObjectToNestedParseObject(mongoObject[key]); } } var relationFieldNames = Object.keys(schema.fields).filter(function (fieldName) { return schema.fields[fieldName].type === 'Relation'; }); var relationFields = {}; relationFieldNames.forEach(function (relationFieldName) { relationFields[relationFieldName] = { __type: 'Relation', className: schema.fields[relationFieldName].targetClass }; }); return _extends({}, restObject, relationFields); } default: throw 'unknown js type'; } }; var DateCoder = { JSONToDatabase: function JSONToDatabase(json) { return new Date(json.iso); }, isValidJSON: function isValidJSON(value) { return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null && value.__type === 'Date'; } }; var BytesCoder = { base64Pattern: new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"), isBase64Value: function isBase64Value(object) { if (typeof object !== 'string') { return false; } return this.base64Pattern.test(object); }, databaseToJSON: function databaseToJSON(object) { var value = void 0; if (this.isBase64Value(object)) { value = object; } else { value = object.buffer.toString('base64'); } return { __type: 'Bytes', base64: value }; }, isValidDatabaseObject: function isValidDatabaseObject(object) { return object instanceof mongodb.Binary || this.isBase64Value(object); }, JSONToDatabase: function JSONToDatabase(json) { return new mongodb.Binary(new Buffer(json.base64, 'base64')); }, isValidJSON: function isValidJSON(value) { return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null && value.__type === 'Bytes'; } }; var GeoPointCoder = { databaseToJSON: function databaseToJSON(object) { return { __type: 'GeoPoint', latitude: object[1], longitude: object[0] }; }, isValidDatabaseObject: function isValidDatabaseObject(object) { return object instanceof Array && object.length == 2; }, JSONToDatabase: function JSONToDatabase(json) { return [json.longitude, json.latitude]; }, isValidJSON: function isValidJSON(value) { return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null && value.__type === 'GeoPoint'; } }; var FileCoder = { databaseToJSON: function databaseToJSON(object) { return { __type: 'File', name: object }; }, isValidDatabaseObject: function isValidDatabaseObject(object) { return typeof object === 'string'; }, JSONToDatabase: function JSONToDatabase(json) { return json.name; }, isValidJSON: function isValidJSON(value) { return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null && value.__type === 'File'; } }; module.exports = { transformKey: transformKey, parseObjectToMongoObjectForCreate: parseObjectToMongoObjectForCreate, transformUpdate: transformUpdate, transformWhere: transformWhere, mongoObjectToParseObject: mongoObjectToParseObject }; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| PostgresClient.js | 23.53% | (4 / 17) | 0% | (0 / 8) | 0% | (0 / 1) | 23.53% | (4 / 17) | |
| PostgresConfigParser.js | 15.38% | (4 / 26) | 0% | (0 / 28) | 0% | (0 / 3) | 15.38% | (4 / 26) | |
| PostgresStorageAdapter.js | 7.33% | (60 / 818) | 2.59% | (12 / 464) | 3.85% | (5 / 130) | 5.88% | (46 / 782) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createClient = createClient;
var parser = require('./PostgresConfigParser');
function createClient(uri, databaseOptions) {
var dbOptions = {};
databaseOptions = databaseOptions || {};
if (uri) {
dbOptions = parser.getDatabaseOptionsFromURI(uri);
}
for (var key in databaseOptions) {
dbOptions[key] = databaseOptions[key];
}
var initOptions = dbOptions.initOptions || {};
var pgp = require('pg-promise')(initOptions);
var client = pgp(dbOptions);
if (dbOptions.pgOptions) {
for (var _key in dbOptions.pgOptions) {
pgp.pg.defaults[_key] = dbOptions.pgOptions[_key];
}
}
return client;
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 | 'use strict';
var url = require('url');
function getDatabaseOptionsFromURI(uri) {
var databaseOptions = {};
var parsedURI = url.parse(uri);
var queryParams = parseQueryParams(parsedURI.query);
var authParts = parsedURI.auth ? parsedURI.auth.split(':') : [];
databaseOptions.host = parsedURI.hostname || 'localhost';
databaseOptions.port = parsedURI.port ? parseInt(parsedURI.port) : 5432;
databaseOptions.database = parsedURI.pathname ? parsedURI.pathname.substr(1) : undefined;
databaseOptions.user = authParts.length > 0 ? authParts[0] : '';
databaseOptions.password = authParts.length > 1 ? authParts[1] : '';
databaseOptions.ssl = queryParams.ssl && queryParams.ssl.toLowerCase() === 'true' ? true : false;
databaseOptions.binary = queryParams.binary && queryParams.binary.toLowerCase() === 'true' ? true : false;
databaseOptions.client_encoding = queryParams.client_encoding;
databaseOptions.application_name = queryParams.application_name;
databaseOptions.fallback_application_name = queryParams.fallback_application_name;
if (queryParams.poolSize) {
databaseOptions.poolSize = parseInt(queryParams.poolSize) || 10;
}
return databaseOptions;
}
function parseQueryParams(queryString) {
queryString = queryString || '';
return queryString.split('&').reduce(function (p, c) {
var parts = c.split('=');
p[decodeURIComponent(parts[0])] = parts.length > 1 ? decodeURIComponent(parts.slice(1).join('=')) : '';
return p;
}, {});
}
module.exports = {
parseQueryParams: parseQueryParams,
getDatabaseOptionsFromURI: getDatabaseOptionsFromURI
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | 1 1 20 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PostgresStorageAdapter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _PostgresClient = require('./PostgresClient');
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _sql = require('./sql');
var _sql2 = _interopRequireDefault(_sql);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var PostgresRelationDoesNotExistError = '42P01';
var PostgresDuplicateRelationError = '42P07';
var PostgresDuplicateColumnError = '42701';
var PostgresDuplicateObjectError = '42710';
var PostgresUniqueIndexViolationError = '23505';
var PostgresTransactionAbortedError = '25P02';
var logger = require('../../../logger');
var debug = function debug() {
var args = [].concat(Array.prototype.slice.call(arguments));
args = ['PG: ' + arguments[0]].concat(args.slice(1, args.length));
var log = logger.getLogger();
log.debug.apply(log, args);
};
var parseTypeToPostgresType = function parseTypeToPostgresType(type) {
switch (type.type) {
case 'String':
return 'text';
case 'Date':
return 'timestamp with time zone';
case 'Object':
return 'jsonb';
case 'File':
return 'text';
case 'Boolean':
return 'boolean';
case 'Pointer':
return 'char(10)';
case 'Number':
return 'double precision';
case 'GeoPoint':
return 'point';
case 'Array':
if (type.contents && type.contents.type === 'String') {
return 'text[]';
} else {
return 'jsonb';
}
default:
throw 'no type for ' + JSON.stringify(type) + ' yet';
}
};
var ParseToPosgresComparator = {
'$gt': '>',
'$lt': '<',
'$gte': '>=',
'$lte': '<='
};
var toPostgresValue = function toPostgresValue(value) {
if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {
if (value.__type === 'Date') {
return value.iso;
}
if (value.__type === 'File') {
return value.name;
}
}
return value;
};
var transformValue = function transformValue(value) {
if (value.__type === 'Pointer') {
return value.objectId;
}
return value;
};
// Duplicate from then mongo adapter...
var emptyCLPS = Object.freeze({
find: {},
get: {},
create: {},
update: {},
delete: {},
addField: {}
});
var defaultCLPS = Object.freeze({
find: { '*': true },
get: { '*': true },
create: { '*': true },
update: { '*': true },
delete: { '*': true },
addField: { '*': true }
});
var toParseSchema = function toParseSchema(schema) {
if (schema.className === '_User') {
delete schema.fields._hashed_password;
}
if (schema.fields) {
delete schema.fields._wperm;
delete schema.fields._rperm;
}
var clps = defaultCLPS;
if (schema.classLevelPermissions) {
clps = _extends({}, emptyCLPS, schema.classLevelPermissions);
}
return {
className: schema.className,
fields: schema.fields,
classLevelPermissions: clps
};
};
var toPostgresSchema = function toPostgresSchema(schema) {
if (!schema) {
return schema;
}
schema.fields = schema.fields || {};
schema.fields._wperm = { type: 'Array', contents: { type: 'String' } };
schema.fields._rperm = { type: 'Array', contents: { type: 'String' } };
if (schema.className === '_User') {
schema.fields._hashed_password = { type: 'String' };
schema.fields._password_history = { type: 'Array' };
}
return schema;
};
var handleDotFields = function handleDotFields(object) {
Object.keys(object).forEach(function (fieldName) {
if (fieldName.indexOf('.') > -1) {
var components = fieldName.split('.');
var first = components.shift();
object[first] = object[first] || {};
var currentObj = object[first];
var next = void 0;
var value = object[fieldName];
if (value && value.__op === 'Delete') {
value = undefined;
}
/* eslint-disable no-cond-assign */
while (next = components.shift()) {
/* eslint-enable no-cond-assign */
currentObj[next] = currentObj[next] || {};
if (components.length === 0) {
currentObj[next] = value;
}
currentObj = currentObj[next];
}
delete object[fieldName];
}
});
return object;
};
var validateKeys = function validateKeys(object) {
if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) == 'object') {
for (var key in object) {
if (_typeof(object[key]) == 'object') {
validateKeys(object[key]);
}
if (key.includes('$') || key.includes('.')) {
throw new _node2.default.Error(_node2.default.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters");
}
}
}
};
// Returns the list of join tables on a schema
var joinTablesForSchema = function joinTablesForSchema(schema) {
var list = [];
if (schema) {
Object.keys(schema.fields).forEach(function (field) {
if (schema.fields[field].type === 'Relation') {
list.push('_Join:' + field + ':' + schema.className);
}
});
}
return list;
};
var buildWhereClause = function buildWhereClause(_ref) {
var schema = _ref.schema,
query = _ref.query,
index = _ref.index;
var patterns = [];
var values = [];
var sorts = [];
schema = toPostgresSchema(schema);
var _loop = function _loop(fieldName) {
var isArrayField = schema.fields && schema.fields[fieldName] && schema.fields[fieldName].type === 'Array';
var initialPatternsLength = patterns.length;
var fieldValue = query[fieldName];
// nothingin the schema, it's gonna blow up
if (!schema.fields[fieldName]) {
// as it won't exist
if (fieldValue.$exists === false) {
return 'continue';
}
}
if (fieldName.indexOf('.') >= 0) {
var components = fieldName.split('.').map(function (cmpt, index) {
if (index === 0) {
return '"' + cmpt + '"';
}
return '\'' + cmpt + '\'';
});
var name = components.slice(0, components.length - 1).join('->');
name += '->>' + components[components.length - 1];
patterns.push(name + ' = \'' + fieldValue + '\'');
} else if (typeof fieldValue === 'string') {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'boolean') {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'number') {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue);
index += 2;
} else if (fieldName === '$or' || fieldName === '$and') {
var _values;
var clauses = [];
var clauseValues = [];
fieldValue.forEach(function (subQuery) {
var clause = buildWhereClause({ schema: schema, query: subQuery, index: index });
if (clause.pattern.length > 0) {
clauses.push(clause.pattern);
clauseValues.push.apply(clauseValues, _toConsumableArray(clause.values));
index += clause.values.length;
}
});
var orOrAnd = fieldName === '$or' ? ' OR ' : ' AND ';
patterns.push('(' + clauses.join(orOrAnd) + ')');
(_values = values).push.apply(_values, clauseValues);
}
if (fieldValue.$ne) {
if (isArrayField) {
fieldValue.$ne = JSON.stringify([fieldValue.$ne]);
patterns.push('NOT array_contains($' + index + ':name, $' + (index + 1) + ')');
} else {
if (fieldValue.$ne === null) {
patterns.push('$' + index + ':name <> $' + (index + 1));
} else {
// if not null, we need to manually exclude null
patterns.push('($' + index + ':name <> $' + (index + 1) + ' OR $' + index + ':name IS NULL)');
}
}
// TODO: support arrays
values.push(fieldName, fieldValue.$ne);
index += 2;
}
if (fieldValue.$eq) {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue.$eq);
index += 2;
}
var isInOrNin = Array.isArray(fieldValue.$in) || Array.isArray(fieldValue.$nin);
if (Array.isArray(fieldValue.$in) && isArrayField && schema.fields[fieldName].contents && schema.fields[fieldName].contents.type === 'String') {
var inPatterns = [];
var allowNull = false;
values.push(fieldName);
fieldValue.$in.forEach(function (listElem, listIndex) {
if (listElem === null) {
allowNull = true;
} else {
values.push(listElem);
inPatterns.push('$' + (index + 1 + listIndex - (allowNull ? 1 : 0)));
}
});
if (allowNull) {
patterns.push('($' + index + ':name IS NULL OR $' + index + ':name && ARRAY[' + inPatterns.join(',') + '])');
} else {
patterns.push('$' + index + ':name && ARRAY[' + inPatterns.join(',') + ']');
}
index = index + 1 + inPatterns.length;
} else if (isInOrNin) {
createConstraint = function createConstraint(baseArray, notIn) {
if (baseArray.length > 0) {
var not = notIn ? ' NOT ' : '';
if (isArrayField) {
patterns.push(not + ' array_contains($' + index + ':name, $' + (index + 1) + ')');
values.push(fieldName, JSON.stringify(baseArray));
index += 2;
} else {
var _inPatterns = [];
values.push(fieldName);
baseArray.forEach(function (listElem, listIndex) {
values.push(listElem);
_inPatterns.push('$' + (index + 1 + listIndex));
});
patterns.push('$' + index + ':name ' + not + ' IN (' + _inPatterns.join(',') + ')');
index = index + 1 + _inPatterns.length;
}
} else if (!notIn) {
values.push(fieldName);
patterns.push('$' + index + ':name IS NULL');
index = index + 1;
}
};
if (fieldValue.$in) {
createConstraint(_lodash2.default.flatMap(fieldValue.$in, function (elt) {
return elt;
}), false);
}
if (fieldValue.$nin) {
createConstraint(_lodash2.default.flatMap(fieldValue.$nin, function (elt) {
return elt;
}), true);
}
}
if (Array.isArray(fieldValue.$all) && isArrayField) {
patterns.push('array_contains_all($' + index + ':name, $' + (index + 1) + '::jsonb)');
values.push(fieldName, JSON.stringify(fieldValue.$all));
index += 2;
}
if (typeof fieldValue.$exists !== 'undefined') {
if (fieldValue.$exists) {
patterns.push('$' + index + ':name IS NOT NULL');
} else {
patterns.push('$' + index + ':name IS NULL');
}
values.push(fieldName);
index += 1;
}
if (fieldValue.$nearSphere) {
var point = fieldValue.$nearSphere;
var distance = fieldValue.$maxDistance;
var distanceInKM = distance * 6371 * 1000;
patterns.push('ST_distance_sphere($' + index + ':name::geometry, POINT($' + (index + 1) + ', $' + (index + 2) + ')::geometry) <= $' + (index + 3));
sorts.push('ST_distance_sphere($' + index + ':name::geometry, POINT($' + (index + 1) + ', $' + (index + 2) + ')::geometry) ASC');
values.push(fieldName, point.longitude, point.latitude, distanceInKM);
index += 4;
}
if (fieldValue.$within && fieldValue.$within.$box) {
var box = fieldValue.$within.$box;
var left = box[0].longitude;
var bottom = box[0].latitude;
var right = box[1].longitude;
var top = box[1].latitude;
patterns.push('$' + index + ':name::point <@ $' + (index + 1) + '::box');
values.push(fieldName, '((' + left + ', ' + bottom + '), (' + right + ', ' + top + '))');
index += 2;
}
if (fieldValue.$regex) {
var regex = fieldValue.$regex;
var operator = '~';
var opts = fieldValue.$options;
if (opts) {
if (opts.indexOf('i') >= 0) {
operator = '~*';
}
if (opts.indexOf('x') >= 0) {
regex = removeWhiteSpace(regex);
}
}
regex = processRegexPattern(regex);
patterns.push('$' + index + ':name ' + operator + ' \'$' + (index + 1) + ':raw\'');
values.push(fieldName, regex);
index += 2;
}
if (fieldValue.__type === 'Pointer') {
if (isArrayField) {
patterns.push('array_contains($' + index + ':name, $' + (index + 1) + ')');
values.push(fieldName, JSON.stringify([fieldValue]));
index += 2;
} else {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue.objectId);
index += 2;
}
}
if (fieldValue.__type === 'Date') {
patterns.push('$' + index + ':name = $' + (index + 1));
values.push(fieldName, fieldValue.iso);
index += 2;
}
Object.keys(ParseToPosgresComparator).forEach(function (cmp) {
if (fieldValue[cmp]) {
var pgComparator = ParseToPosgresComparator[cmp];
patterns.push('$' + index + ':name ' + pgComparator + ' $' + (index + 1));
values.push(fieldName, toPostgresValue(fieldValue[cmp]));
index += 2;
}
});
if (initialPatternsLength === patterns.length) {
throw new _node2.default.Error(_node2.default.Error.OPERATION_FORBIDDEN, 'Postgres doesn\'t support this query type yet ' + JSON.stringify(fieldValue));
}
};
for (var fieldName in query) {
var createConstraint;
var _ret = _loop(fieldName);
if (_ret === 'continue') continue;
}
values = values.map(transformValue);
return { pattern: patterns.join(' AND '), values: values, sorts: sorts };
};
var PostgresStorageAdapter = exports.PostgresStorageAdapter = function () {
// Private
function PostgresStorageAdapter(_ref2) {
var uri = _ref2.uri,
_ref2$collectionPrefi = _ref2.collectionPrefix,
collectionPrefix = _ref2$collectionPrefi === undefined ? '' : _ref2$collectionPrefi,
databaseOptions = _ref2.databaseOptions;
_classCallCheck(this, PostgresStorageAdapter);
this._collectionPrefix = collectionPrefix;
this._client = (0, _PostgresClient.createClient)(uri, databaseOptions);
}
_createClass(PostgresStorageAdapter, [{
key: '_ensureSchemaCollectionExists',
value: function _ensureSchemaCollectionExists(conn) {
conn = conn || this._client;
return conn.none('CREATE TABLE IF NOT EXISTS "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )').catch(function (error) {
if (error.code === PostgresDuplicateRelationError || error.code === PostgresUniqueIndexViolationError || error.code === PostgresDuplicateObjectError) {
// Table already exists, must have been created by a different request. Ignore error.
} else {
throw error;
}
});
}
}, {
key: 'classExists',
value: function classExists(name) {
return this._client.one('SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1)', [name]).then(function (res) {
return res.exists;
});
}
}, {
key: 'setClassLevelPermissions',
value: function setClassLevelPermissions(className, CLPs) {
var _this = this;
return this._ensureSchemaCollectionExists().then(function () {
var values = [className, 'schema', 'classLevelPermissions', JSON.stringify(CLPs)];
return _this._client.none('UPDATE "_SCHEMA" SET $2:name = json_object_set_key($2:name, $3::text, $4::jsonb) WHERE "className"=$1 ', values);
});
}
}, {
key: 'createClass',
value: function createClass(className, schema) {
var _this2 = this;
return this._client.tx(function (t) {
var q1 = _this2.createTable(className, schema, t);
var q2 = t.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className: className, schema: schema });
return t.batch([q1, q2]);
}).then(function () {
return toParseSchema(schema);
}).catch(function (err) {
if (Array.isArray(err.data) && err.data.length > 1 && err.data[0].result.code === PostgresTransactionAbortedError) {
err = err.data[1].result;
}
if (err.code === PostgresUniqueIndexViolationError && err.detail.includes(className)) {
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'Class ' + className + ' already exists.');
}
throw err;
});
}
// Just create a table, do not insert in schema
}, {
key: 'createTable',
value: function createTable(className, schema, conn) {
conn = conn || this._client;
debug('createTable', className, schema);
var valuesArray = [];
var patternsArray = [];
var fields = Object.assign({}, schema.fields);
if (className === '_User') {
fields._email_verify_token_expires_at = { type: 'Date' };
fields._email_verify_token = { type: 'String' };
fields._account_lockout_expires_at = { type: 'Date' };
fields._failed_login_count = { type: 'Number' };
fields._perishable_token = { type: 'String' };
fields._perishable_token_expires_at = { type: 'Date' };
fields._password_changed_at = { type: 'Date' };
fields._password_history = { type: 'Array' };
}
var index = 2;
var relations = [];
Object.keys(fields).forEach(function (fieldName) {
var parseType = fields[fieldName];
// Skip when it's a relation
// We'll create the tables later
if (parseType.type === 'Relation') {
relations.push(fieldName);
return;
}
if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) {
parseType.contents = { type: 'String' };
}
valuesArray.push(fieldName);
valuesArray.push(parseTypeToPostgresType(parseType));
patternsArray.push('$' + index + ':name $' + (index + 1) + ':raw');
if (fieldName === 'objectId') {
patternsArray.push('PRIMARY KEY ($' + index + ':name)');
}
index = index + 2;
});
var qs = 'CREATE TABLE IF NOT EXISTS $1:name (' + patternsArray.join(',') + ')';
var values = [className].concat(valuesArray);
return this._ensureSchemaCollectionExists(conn).then(function () {
return conn.none(qs, values);
}).catch(function (error) {
if (error.code === PostgresDuplicateRelationError) {
// Table already exists, must have been created by a different request. Ignore error.
} else {
throw error;
}
}).then(function () {
// Create the relation tables
return Promise.all(relations.map(function (fieldName) {
return conn.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', { joinTable: '_Join:' + fieldName + ':' + className });
}));
});
}
}, {
key: 'addFieldIfNotExists',
value: function addFieldIfNotExists(className, fieldName, type) {
var _this3 = this;
// TODO: Must be revised for invalid logic...
debug('addFieldIfNotExists', { className: className, fieldName: fieldName, type: type });
return this._client.tx("addFieldIfNotExists", function (t) {
var promise = Promise.resolve();
if (type.type !== 'Relation') {
promise = t.none('ALTER TABLE $<className:name> ADD COLUMN $<fieldName:name> $<postgresType:raw>', {
className: className,
fieldName: fieldName,
postgresType: parseTypeToPostgresType(type)
}).catch(function (error) {
if (error.code === PostgresRelationDoesNotExistError) {
return _this3.createClass(className, { fields: _defineProperty({}, fieldName, type) });
} else if (error.code === PostgresDuplicateColumnError) {
// Column already exists, created by other request. Carry on to
// See if it's the right type.
} else {
throw error;
}
});
} else {
promise = t.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', { joinTable: '_Join:' + fieldName + ':' + className });
}
return promise.then(function () {
return t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $<className>', { className: className });
}).then(function (result) {
if (fieldName in result[0].schema.fields) {
throw "Attempted to add a field that already exists";
} else {
result[0].schema.fields[fieldName] = type;
return t.none('UPDATE "_SCHEMA" SET "schema"=$<schema> WHERE "className"=$<className>', { schema: result[0].schema, className: className });
}
});
});
}
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
// and resolves with false if it wasn't (eg. a join table). Rejects if deletion was impossible.
}, {
key: 'deleteClass',
value: function deleteClass(className) {
var _this4 = this;
return Promise.resolve().then(function () {
var operations = [['DROP TABLE IF EXISTS $1:name', [className]], ['DELETE FROM "_SCHEMA" WHERE "className"=$1', [className]]];
return _this4._client.tx(function (t) {
return t.batch(operations.map(function (statement) {
return t.none(statement[0], statement[1]);
}));
});
}).then(function () {
// resolves with false when _Join table
return className.indexOf('_Join:') != 0;
});
}
// Delete all data known to this adapter. Used for testing.
}, {
key: 'deleteAllClasses',
value: function deleteAllClasses() {
var _this5 = this;
var now = new Date().getTime();
debug('deleteAllClasses');
return this._client.any('SELECT * FROM "_SCHEMA"').then(function (results) {
var joins = results.reduce(function (list, schema) {
return list.concat(joinTablesForSchema(schema.schema));
}, []);
var classes = ['_SCHEMA', '_PushStatus', '_JobStatus', '_Hooks', '_GlobalConfig'].concat(_toConsumableArray(results.map(function (result) {
return result.className;
})), _toConsumableArray(joins));
return _this5._client.tx(function (t) {
return t.batch(classes.map(function (className) {
return t.none('DROP TABLE IF EXISTS $<className:name>', { className: className });
}));
});
}, function (error) {
if (error.code === PostgresRelationDoesNotExistError) {
// No _SCHEMA collection. Don't delete anything.
return;
} else {
throw error;
}
}).then(function () {
debug('deleteAllClasses done in ' + (new Date().getTime() - now));
});
}
// Remove the column and all the data. For Relations, the _Join collection is handled
// specially, this function does not delete _Join columns. It should, however, indicate
// that the relation fields does not exist anymore. In mongo, this means removing it from
// the _SCHEMA collection. There should be no actual data in the collection under the same name
// as the relation column, so it's fine to attempt to delete it. If the fields listed to be
// deleted do not exist, this function should return successfully anyways. Checking for
// attempts to delete non-existent fields is the responsibility of Parse Server.
// This function is not obligated to delete fields atomically. It is given the field
// names in a list so that databases that are capable of deleting fields atomically
// may do so.
// Returns a Promise.
}, {
key: 'deleteFields',
value: function deleteFields(className, schema, fieldNames) {
var _this6 = this;
debug('deleteFields', className, fieldNames);
return Promise.resolve().then(function () {
fieldNames = fieldNames.reduce(function (list, fieldName) {
var field = schema.fields[fieldName];
if (field.type !== 'Relation') {
list.push(fieldName);
}
delete schema.fields[fieldName];
return list;
}, []);
var values = [className].concat(_toConsumableArray(fieldNames));
var columns = fieldNames.map(function (name, idx) {
return '$' + (idx + 2) + ':name';
}).join(',');
var doBatch = function doBatch(t) {
var batch = [t.none('UPDATE "_SCHEMA" SET "schema"=$<schema> WHERE "className"=$<className>', { schema: schema, className: className })];
if (values.length > 1) {
batch.push(t.none('ALTER TABLE $1:name DROP COLUMN ' + columns, values));
}
return batch;
};
return _this6._client.tx(function (t) {
return t.batch(doBatch(t));
});
});
}
// Return a promise for all schemas known to this adapter, in Parse format. In case the
// schemas cannot be retrieved, returns a promise that rejects. Requirements for the
// rejection reason are TBD.
}, {
key: 'getAllClasses',
value: function getAllClasses() {
var _this7 = this;
return this._ensureSchemaCollectionExists().then(function () {
return _this7._client.map('SELECT * FROM "_SCHEMA"', null, function (row) {
return _extends({ className: row.className }, row.schema);
});
}).then(function (res) {
return res.map(toParseSchema);
});
}
// Return a promise for the schema with the given name, in Parse format. If
// this adapter doesn't know about the schema, return a promise that rejects with
// undefined as the reason.
}, {
key: 'getClass',
value: function getClass(className) {
debug('getClass', className);
return this._client.any('SELECT * FROM "_SCHEMA" WHERE "className"=$<className>', { className: className }).then(function (result) {
if (result.length === 1) {
return result[0].schema;
} else {
throw undefined;
}
}).then(toParseSchema);
}
// TODO: remove the mongo format dependency in the return value
}, {
key: 'createObject',
value: function createObject(className, schema, object) {
debug('createObject', className, object);
var columnsArray = [];
var valuesArray = [];
schema = toPostgresSchema(schema);
var geoPoints = {};
object = handleDotFields(object);
validateKeys(object);
Object.keys(object).forEach(function (fieldName) {
var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
if (authDataMatch) {
var provider = authDataMatch[1];
object['authData'] = object['authData'] || {};
object['authData'][provider] = object[fieldName];
delete object[fieldName];
fieldName = 'authData';
}
columnsArray.push(fieldName);
if (!schema.fields[fieldName] && className === '_User') {
if (fieldName === '_email_verify_token' || fieldName === '_failed_login_count' || fieldName === '_perishable_token' || fieldName === '_password_history') {
valuesArray.push(object[fieldName]);
}
if (fieldName === '_email_verify_token_expires_at') {
if (object[fieldName]) {
valuesArray.push(object[fieldName].iso);
} else {
valuesArray.push(null);
}
}
if (fieldName === '_account_lockout_expires_at' || fieldName === '_perishable_token_expires_at' || fieldName === '_password_changed_at') {
if (object[fieldName]) {
valuesArray.push(object[fieldName].iso);
} else {
valuesArray.push(null);
}
}
return;
}
switch (schema.fields[fieldName].type) {
case 'Date':
if (object[fieldName]) {
valuesArray.push(object[fieldName].iso);
} else {
valuesArray.push(null);
}
break;
case 'Pointer':
valuesArray.push(object[fieldName].objectId);
break;
case 'Array':
if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) {
valuesArray.push(object[fieldName]);
} else {
valuesArray.push(JSON.stringify(object[fieldName]));
}
break;
case 'Object':
case 'String':
case 'Number':
case 'Boolean':
valuesArray.push(object[fieldName]);
break;
case 'File':
valuesArray.push(object[fieldName].name);
break;
case 'GeoPoint':
// pop the point and process later
geoPoints[fieldName] = object[fieldName];
columnsArray.pop();
break;
default:
throw 'Type ' + schema.fields[fieldName].type + ' not supported yet';
}
});
columnsArray = columnsArray.concat(Object.keys(geoPoints));
var initialValues = valuesArray.map(function (val, index) {
var termination = '';
var fieldName = columnsArray[index];
if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) {
termination = '::text[]';
} else if (schema.fields[fieldName] && schema.fields[fieldName].type === 'Array') {
termination = '::jsonb';
}
return '$' + (index + 2 + columnsArray.length) + termination;
});
var geoPointsInjects = Object.keys(geoPoints).map(function (key) {
var value = geoPoints[key];
valuesArray.push(value.longitude, value.latitude);
var l = valuesArray.length + columnsArray.length;
return 'POINT($' + l + ', $' + (l + 1) + ')';
});
var columnsPattern = columnsArray.map(function (col, index) {
return '$' + (index + 2) + ':name';
}).join(',');
var valuesPattern = initialValues.concat(geoPointsInjects).join(',');
var qs = 'INSERT INTO $1:name (' + columnsPattern + ') VALUES (' + valuesPattern + ')';
var values = [className].concat(_toConsumableArray(columnsArray), valuesArray);
debug(qs, values);
return this._client.any(qs, values).then(function () {
return { ops: [object] };
}).catch(function (error) {
if (error.code === PostgresUniqueIndexViolationError) {
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
} else {
throw error;
}
});
}
// Remove all objects that match the given Parse Query.
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
}, {
key: 'deleteObjectsByQuery',
value: function deleteObjectsByQuery(className, schema, query) {
debug('deleteObjectsByQuery', className, query);
var values = [className];
var index = 2;
var where = buildWhereClause({ schema: schema, index: index, query: query });
values.push.apply(values, _toConsumableArray(where.values));
if (Object.keys(query).length === 0) {
where.pattern = 'TRUE';
}
var qs = 'WITH deleted AS (DELETE FROM $1:name WHERE ' + where.pattern + ' RETURNING *) SELECT count(*) FROM deleted';
debug(qs, values);
return this._client.one(qs, values, function (a) {
return +a.count;
}).then(function (count) {
if (count === 0) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Object not found.');
} else {
return count;
}
});
}
// Return value not currently well specified.
}, {
key: 'findOneAndUpdate',
value: function findOneAndUpdate(className, schema, query, update) {
debug('findOneAndUpdate', className, query, update);
return this.updateObjectsByQuery(className, schema, query, update).then(function (val) {
return val[0];
});
}
// Apply the update to all objects that match the given Parse Query.
}, {
key: 'updateObjectsByQuery',
value: function updateObjectsByQuery(className, schema, query, update) {
debug('updateObjectsByQuery', className, query, update);
var updatePatterns = [];
var values = [className];
var index = 2;
schema = toPostgresSchema(schema);
var originalUpdate = _extends({}, update);
update = handleDotFields(update);
// Resolve authData first,
// So we don't end up with multiple key updates
for (var fieldName in update) {
var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
if (authDataMatch) {
var provider = authDataMatch[1];
var value = update[fieldName];
delete update[fieldName];
update['authData'] = update['authData'] || {};
update['authData'][provider] = value;
}
}
var _loop2 = function _loop2(_fieldName) {
var fieldValue = update[_fieldName];
if (fieldValue === null) {
updatePatterns.push('$' + index + ':name = NULL');
values.push(_fieldName);
index += 1;
} else if (_fieldName == 'authData') {
// This recursively sets the json_object
// Only 1 level deep
var generate = function generate(jsonb, key, value) {
return 'json_object_set_key(COALESCE(' + jsonb + ', \'{}\'::jsonb), ' + key + ', ' + value + ')::jsonb';
};
var lastKey = '$' + index + ':name';
var fieldNameIndex = index;
index += 1;
values.push(_fieldName);
var _update = Object.keys(fieldValue).reduce(function (lastKey, key) {
var str = generate(lastKey, '$' + index + '::text', '$' + (index + 1) + '::jsonb');
index += 2;
var value = fieldValue[key];
if (value) {
if (value.__op === 'Delete') {
value = null;
} else {
value = JSON.stringify(value);
}
}
values.push(key, value);
return str;
}, lastKey);
updatePatterns.push('$' + fieldNameIndex + ':name = ' + _update);
} else if (fieldValue.__op === 'Increment') {
updatePatterns.push('$' + index + ':name = COALESCE($' + index + ':name, 0) + $' + (index + 1));
values.push(_fieldName, fieldValue.amount);
index += 2;
} else if (fieldValue.__op === 'Add') {
updatePatterns.push('$' + index + ':name = array_add(COALESCE($' + index + ':name, \'[]\'::jsonb), $' + (index + 1) + '::jsonb)');
values.push(_fieldName, JSON.stringify(fieldValue.objects));
index += 2;
} else if (fieldValue.__op === 'Delete') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, null);
index += 2;
} else if (fieldValue.__op === 'Remove') {
updatePatterns.push('$' + index + ':name = array_remove(COALESCE($' + index + ':name, \'[]\'::jsonb), $' + (index + 1) + '::jsonb)');
values.push(_fieldName, JSON.stringify(fieldValue.objects));
index += 2;
} else if (fieldValue.__op === 'AddUnique') {
updatePatterns.push('$' + index + ':name = array_add_unique(COALESCE($' + index + ':name, \'[]\'::jsonb), $' + (index + 1) + '::jsonb)');
values.push(_fieldName, JSON.stringify(fieldValue.objects));
index += 2;
} else if (_fieldName === 'updatedAt') {
//TODO: stop special casing this. It should check for __type === 'Date' and use .iso
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'string') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'boolean') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue);
index += 2;
} else if (fieldValue.__type === 'Pointer') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue.objectId);
index += 2;
} else if (fieldValue.__type === 'Date') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, toPostgresValue(fieldValue));
index += 2;
} else if (fieldValue instanceof Date) {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue);
index += 2;
} else if (fieldValue.__type === 'File') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, toPostgresValue(fieldValue));
index += 2;
} else if (fieldValue.__type === 'GeoPoint') {
updatePatterns.push('$' + index + ':name = POINT($' + (index + 1) + ', $' + (index + 2) + ')');
values.push(_fieldName, fieldValue.latitude, fieldValue.longitude);
index += 3;
} else if (fieldValue.__type === 'Relation') {
// noop
} else if (typeof fieldValue === 'number') {
updatePatterns.push('$' + index + ':name = $' + (index + 1));
values.push(_fieldName, fieldValue);
index += 2;
} else if ((typeof fieldValue === 'undefined' ? 'undefined' : _typeof(fieldValue)) === 'object' && schema.fields[_fieldName] && schema.fields[_fieldName].type === 'Object') {
// Gather keys to increment
var keysToIncrement = Object.keys(originalUpdate).filter(function (k) {
// choose top level fields that have a delete operation set
return originalUpdate[k].__op === 'Increment' && k.split('.').length === 2 && k.split(".")[0] === _fieldName;
}).map(function (k) {
return k.split('.')[1];
});
var incrementPatterns = '';
if (keysToIncrement.length > 0) {
incrementPatterns = ' || ' + keysToIncrement.map(function (c) {
var amount = fieldValue[c].amount;
return 'CONCAT(\'{"' + c + '":\', COALESCE($' + index + ':name->>\'' + c + '\',\'0\')::int + ' + amount + ', \'}\')::jsonb';
}).join(' || ');
// Strip the keys
keysToIncrement.forEach(function (key) {
delete fieldValue[key];
});
}
var keysToDelete = Object.keys(originalUpdate).filter(function (k) {
// choose top level fields that have a delete operation set
return originalUpdate[k].__op === 'Delete' && k.split('.').length === 2 && k.split(".")[0] === _fieldName;
}).map(function (k) {
return k.split('.')[1];
});
var deletePatterns = keysToDelete.reduce(function (p, c, i) {
return p + (' - \'$' + (index + 1 + i) + ':value\'');
}, '');
updatePatterns.push('$' + index + ':name = ( COALESCE($' + index + ':name, \'{}\'::jsonb) ' + deletePatterns + ' ' + incrementPatterns + ' || $' + (index + 1 + keysToDelete.length) + '::jsonb )');
values.push.apply(values, [_fieldName].concat(_toConsumableArray(keysToDelete), [JSON.stringify(fieldValue)]));
index += 2 + keysToDelete.length;
} else if (Array.isArray(fieldValue) && schema.fields[_fieldName] && schema.fields[_fieldName].type === 'Array') {
var expectedType = parseTypeToPostgresType(schema.fields[_fieldName]);
if (expectedType === 'text[]') {
updatePatterns.push('$' + index + ':name = $' + (index + 1) + '::text[]');
} else {
var type = 'text';
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = fieldValue[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var elt = _step.value;
if ((typeof elt === 'undefined' ? 'undefined' : _typeof(elt)) == 'object') {
type = 'json';
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
updatePatterns.push('$' + index + ':name = array_to_json($' + (index + 1) + '::' + type + '[])::jsonb');
}
values.push(_fieldName, fieldValue);
index += 2;
} else {
debug('Not supported update', _fieldName, fieldValue);
return {
v: Promise.reject(new _node2.default.Error(_node2.default.Error.OPERATION_FORBIDDEN, 'Postgres doesn\'t support update ' + JSON.stringify(fieldValue) + ' yet'))
};
}
};
for (var _fieldName in update) {
var _ret2 = _loop2(_fieldName);
if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v;
}
var where = buildWhereClause({ schema: schema, index: index, query: query });
values.push.apply(values, _toConsumableArray(where.values));
var qs = 'UPDATE $1:name SET ' + updatePatterns.join(',') + ' WHERE ' + where.pattern + ' RETURNING *';
debug('update: ', qs, values);
return this._client.any(qs, values); // TODO: This is unsafe, verification is needed, or a different query method;
}
// Hopefully, we can get rid of this. It's only used for config and hooks.
}, {
key: 'upsertOneObject',
value: function upsertOneObject(className, schema, query, update) {
var _this8 = this;
debug('upsertOneObject', { className: className, query: query, update: update });
var createValue = Object.assign({}, query, update);
return this.createObject(className, schema, createValue).catch(function (err) {
// ignore duplicate value errors as it's upsert
if (err.code === _node2.default.Error.DUPLICATE_VALUE) {
return _this8.findOneAndUpdate(className, schema, query, update);
}
throw err;
});
}
}, {
key: 'find',
value: function find(className, schema, query, _ref3) {
var _values2;
var skip = _ref3.skip,
limit = _ref3.limit,
sort = _ref3.sort,
keys = _ref3.keys;
debug('find', className, query, { skip: skip, limit: limit, sort: sort, keys: keys });
var hasLimit = limit !== undefined;
var hasSkip = skip !== undefined;
var values = [className];
var where = buildWhereClause({ schema: schema, query: query, index: 2 });
(_values2 = values).push.apply(_values2, _toConsumableArray(where.values));
var wherePattern = where.pattern.length > 0 ? 'WHERE ' + where.pattern : '';
var limitPattern = hasLimit ? 'LIMIT $' + (values.length + 1) : '';
if (hasLimit) {
values.push(limit);
}
var skipPattern = hasSkip ? 'OFFSET $' + (values.length + 1) : '';
if (hasSkip) {
values.push(skip);
}
var sortPattern = '';
if (sort) {
var sorting = Object.keys(sort).map(function (key) {
// Using $idx pattern gives: non-integer constant in ORDER BY
if (sort[key] === 1) {
return '"' + key + '" ASC';
}
return '"' + key + '" DESC';
}).join(',');
sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? 'ORDER BY ' + sorting : '';
}
if (where.sorts && Object.keys(where.sorts).length > 0) {
sortPattern = 'ORDER BY ' + where.sorts.join(',');
}
var columns = '*';
if (keys) {
// Exclude empty keys
keys = keys.filter(function (key) {
return key.length > 0;
});
columns = keys.map(function (key, index) {
return '$' + (index + values.length + 1) + ':name';
}).join(',');
values = values.concat(keys);
}
var qs = 'SELECT ' + columns + ' FROM $1:name ' + wherePattern + ' ' + sortPattern + ' ' + limitPattern + ' ' + skipPattern;
debug(qs, values);
return this._client.any(qs, values).catch(function (err) {
// Query on non existing table, don't crash
if (err.code === PostgresRelationDoesNotExistError) {
return [];
}
return Promise.reject(err);
}).then(function (results) {
return results.map(function (object) {
Object.keys(schema.fields).forEach(function (fieldName) {
if (schema.fields[fieldName].type === 'Pointer' && object[fieldName]) {
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass };
}
if (schema.fields[fieldName].type === 'Relation') {
object[fieldName] = {
__type: "Relation",
className: schema.fields[fieldName].targetClass
};
}
if (object[fieldName] && schema.fields[fieldName].type === 'GeoPoint') {
object[fieldName] = {
__type: "GeoPoint",
latitude: object[fieldName].y,
longitude: object[fieldName].x
};
}
if (object[fieldName] && schema.fields[fieldName].type === 'File') {
object[fieldName] = {
__type: 'File',
name: object[fieldName]
};
}
});
//TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field.
if (object.createdAt) {
object.createdAt = object.createdAt.toISOString();
}
if (object.updatedAt) {
object.updatedAt = object.updatedAt.toISOString();
}
if (object.expiresAt) {
object.expiresAt = { __type: 'Date', iso: object.expiresAt.toISOString() };
}
if (object._email_verify_token_expires_at) {
object._email_verify_token_expires_at = { __type: 'Date', iso: object._email_verify_token_expires_at.toISOString() };
}
if (object._account_lockout_expires_at) {
object._account_lockout_expires_at = { __type: 'Date', iso: object._account_lockout_expires_at.toISOString() };
}
if (object._perishable_token_expires_at) {
object._perishable_token_expires_at = { __type: 'Date', iso: object._perishable_token_expires_at.toISOString() };
}
if (object._password_changed_at) {
object._password_changed_at = { __type: 'Date', iso: object._password_changed_at.toISOString() };
}
for (var fieldName in object) {
if (object[fieldName] === null) {
delete object[fieldName];
}
if (object[fieldName] instanceof Date) {
object[fieldName] = { __type: 'Date', iso: object[fieldName].toISOString() };
}
}
return object;
});
});
}
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
// currently know which fields are nullable and which aren't, we ignore that criteria.
// As such, we shouldn't expose this function to users of parse until we have an out-of-band
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
// which is why we use sparse indexes.
}, {
key: 'ensureUniqueness',
value: function ensureUniqueness(className, schema, fieldNames) {
// Use the same name for every ensureUniqueness attempt, because postgres
// Will happily create the same index with multiple names.
var constraintName = 'unique_' + fieldNames.sort().join('_');
var constraintPatterns = fieldNames.map(function (fieldName, index) {
return '$' + (index + 3) + ':name';
});
var qs = 'ALTER TABLE $1:name ADD CONSTRAINT $2:name UNIQUE (' + constraintPatterns.join(',') + ')';
return this._client.none(qs, [className, constraintName].concat(_toConsumableArray(fieldNames))).catch(function (error) {
if (error.code === PostgresDuplicateRelationError && error.message.includes(constraintName)) {
// Index already exists. Ignore error.
} else if (error.code === PostgresUniqueIndexViolationError && error.message.includes(constraintName)) {
// Cast the error into the proper parse error
throw new _node2.default.Error(_node2.default.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
} else {
throw error;
}
});
}
// Executes a count.
}, {
key: 'count',
value: function count(className, schema, query) {
debug('count', className, query);
var values = [className];
var where = buildWhereClause({ schema: schema, query: query, index: 2 });
values.push.apply(values, _toConsumableArray(where.values));
var wherePattern = where.pattern.length > 0 ? 'WHERE ' + where.pattern : '';
var qs = 'SELECT count(*) FROM $1:name ' + wherePattern;
return this._client.one(qs, values, function (a) {
return +a.count;
}).catch(function (err) {
if (err.code === PostgresRelationDoesNotExistError) {
return 0;
}
throw err;
});
}
}, {
key: 'performInitialization',
value: function performInitialization(_ref4) {
var _this9 = this;
var VolatileClassesSchemas = _ref4.VolatileClassesSchemas;
debug('performInitialization');
var promises = VolatileClassesSchemas.map(function (schema) {
return _this9.createTable(schema.className, schema).catch(function (err) {
if (err.code === PostgresDuplicateRelationError || err.code === _node2.default.Error.INVALID_CLASS_NAME) {
return Promise.resolve();
}
throw err;
});
});
return Promise.all(promises).then(function () {
return _this9._client.tx(function (t) {
return t.batch([t.none(_sql2.default.misc.jsonObjectSetKeys), t.none(_sql2.default.array.add), t.none(_sql2.default.array.addUnique), t.none(_sql2.default.array.remove), t.none(_sql2.default.array.containsAll), t.none(_sql2.default.array.contains)]);
});
}).then(function (data) {
debug('initializationDone in ' + data.duration);
}).catch(function (error) {
/* eslint-disable no-console */
console.error(error);
});
}
}]);
return PostgresStorageAdapter;
}();
function removeWhiteSpace(regex) {
if (!regex.endsWith('\n')) {
regex += '\n';
}
// remove non escaped comments
return regex.replace(/([^\\])#.*\n/gmi, '$1')
// remove lines starting with a comment
.replace(/^#.*\n/gmi, '')
// remove non escaped whitespace
.replace(/([^\\])\s+/gmi, '$1')
// remove whitespace at the beginning of a line
.replace(/^\s+/, '').trim();
}
function processRegexPattern(s) {
if (s && s.startsWith('^')) {
// regex for startsWith
return '^' + literalizeRegexPart(s.slice(1));
} else if (s && s.endsWith('$')) {
// regex for endsWith
return literalizeRegexPart(s.slice(0, s.length - 1)) + '$';
}
// regex for contains
return literalizeRegexPart(s);
}
function createLiteralRegex(remaining) {
return remaining.split('').map(function (c) {
if (c.match(/[0-9a-zA-Z]/) !== null) {
// don't escape alphanumeric characters
return c;
}
// escape everything else (single quotes with single quotes, everything else with a backslash)
return c === '\'' ? '\'\'' : '\\' + c;
}).join('');
}
function literalizeRegexPart(s) {
var matcher1 = /\\Q((?!\\E).*)\\E$/;
var result1 = s.match(matcher1);
if (result1 && result1.length > 1 && result1.index > -1) {
// process regex that has a beginning and an end specified for the literal text
var prefix = s.substr(0, result1.index);
var remaining = result1[1];
return literalizeRegexPart(prefix) + createLiteralRegex(remaining);
}
// process regex that has a beginning specified for the literal text
var matcher2 = /\\Q((?!\\E).*)$/;
var result2 = s.match(matcher2);
if (result2 && result2.length > 1 && result2.index > -1) {
var _prefix = s.substr(0, result2.index);
var _remaining = result2[1];
return literalizeRegexPart(_prefix) + createLiteralRegex(_remaining);
}
// remove all instances of \Q and \E from the remaining text & escape single quotes
return s.replace(/([^\\])(\\E)/, '$1').replace(/([^\\])(\\Q)/, '$1').replace(/^\\E/, '').replace(/^\\Q/, '').replace(/([^'])'/, '$1\'\'').replace(/^'([^'])/, '\'\'$1');
}
exports.default = PostgresStorageAdapter;
module.exports = PostgresStorageAdapter; // Required for tests
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 88.89% | (8 / 9) | 50% | (1 / 2) | 100% | (1 / 1) | 88.89% | (8 / 9) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 1 1 6 6 6 6 | 'use strict';
var QueryFile = require('pg-promise').QueryFile;
var path = require('path');
module.exports = {
array: {
add: sql('array/add.sql'),
addUnique: sql('array/add-unique.sql'),
contains: sql('array/contains.sql'),
containsAll: sql('array/contains-all.sql'),
remove: sql('array/remove.sql')
},
misc: {
jsonObjectSetKeys: sql('misc/json-object-set-keys.sql')
}
};
///////////////////////////////////////////////
// Helper for linking to external query files;
function sql(file) {
var fullPath = path.join(__dirname, file); // generating full path;
var qf = new QueryFile(fullPath, { minify: true });
Iif (qf.error) {
throw qf.error;
}
return qf;
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AdaptableController.js | 85.71% | (48 / 56) | 55.88% | (19 / 34) | 81.25% | (13 / 16) | 83.78% | (31 / 37) | |
| AnalyticsController.js | 62.96% | (34 / 54) | 37.84% | (14 / 37) | 33.33% | (6 / 18) | 55.17% | (16 / 29) | |
| CacheController.js | 53.25% | (41 / 77) | 37.84% | (14 / 37) | 31.82% | (7 / 22) | 44.23% | (23 / 52) | |
| DatabaseController.js | 10.33% | (63 / 610) | 3% | (11 / 367) | 1.53% | (2 / 131) | 10.43% | (60 / 575) | |
| FilesController.js | 47.67% | (41 / 86) | 25.71% | (18 / 70) | 31.58% | (6 / 19) | 38.98% | (23 / 59) | |
| HooksController.js | 26.92% | (42 / 156) | 14.43% | (14 / 97) | 12.82% | (5 / 39) | 15.5% | (20 / 129) | |
| LiveQueryController.js | 50% | (23 / 46) | 22.73% | (5 / 22) | 40% | (4 / 10) | 33.33% | (10 / 30) | |
| LoggerController.js | 50.39% | (64 / 127) | 29.21% | (26 / 89) | 57.69% | (15 / 26) | 41.24% | (40 / 97) | |
| PushController.js | 40% | (34 / 85) | 16% | (8 / 50) | 27.78% | (5 / 18) | 27.94% | (19 / 68) | |
| SchemaCache.js | 38.16% | (29 / 76) | 18.18% | (8 / 44) | 26.32% | (5 / 19) | 25.42% | (15 / 59) | |
| SchemaController.js | 16.02% | (78 / 487) | 3.13% | (11 / 352) | 6.19% | (6 / 97) | 14.48% | (65 / 449) | |
| UserController.js | 27.88% | (46 / 165) | 15.53% | (16 / 103) | 18.18% | (6 / 33) | 22.4% | (28 / 125) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 1 1 4 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 2 2 2 2 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AdaptableController = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _Config = require("../Config");
var _Config2 = _interopRequireDefault(_Config);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
AdaptableController.js
AdaptableController is the base class for all controllers
that support adapter,
The super class takes care of creating the right instance for the adapter
based on the parameters passed
*/
// _adapter is private, use Symbol
var _adapter = Symbol();
var AdaptableController = exports.AdaptableController = function () {
function AdaptableController(adapter, appId, options) {
_classCallCheck(this, AdaptableController);
this.options = options;
this.appId = appId;
this.adapter = adapter;
}
_createClass(AdaptableController, [{
key: "expectedAdapterType",
value: function expectedAdapterType() {
throw new Error("Subclasses should implement expectedAdapterType()");
}
}, {
key: "validateAdapter",
value: function validateAdapter(adapter) {
AdaptableController.validateAdapter(adapter, this);
}
}, {
key: "adapter",
set: function set(adapter) {
this.validateAdapter(adapter);
this[_adapter] = adapter;
},
get: function get() {
return this[_adapter];
}
}, {
key: "config",
get: function get() {
return new _Config2.default(this.appId);
}
}], [{
key: "validateAdapter",
value: function validateAdapter(adapter, self, ExpectedType) {
Iif (!adapter) {
throw new Error(this.constructor.name + " requires an adapter");
}
var Type = ExpectedType || self.expectedAdapterType();
// Allow skipping for testing
Iif (!Type) {
return;
}
// Makes sure the prototype matches
var mismatches = Object.getOwnPropertyNames(Type.prototype).reduce(function (obj, key) {
var adapterType = _typeof(adapter[key]);
var expectedType = _typeof(Type.prototype[key]);
Iif (adapterType !== expectedType) {
obj[key] = {
expected: expectedType,
actual: adapterType
};
}
return obj;
}, {});
Iif (Object.keys(mismatches).length > 0) {
throw new Error("Adapter prototype don't match expected prototype", adapter, mismatches);
}
}
}]);
return AdaptableController;
}();
exports.default = AdaptableController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AnalyticsController = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _AdaptableController2 = require('./AdaptableController');
var _AdaptableController3 = _interopRequireDefault(_AdaptableController2);
var _AnalyticsAdapter = require('../Adapters/Analytics/AnalyticsAdapter');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var AnalyticsController = exports.AnalyticsController = function (_AdaptableController) {
_inherits(AnalyticsController, _AdaptableController);
function AnalyticsController() {
_classCallCheck(this, AnalyticsController);
return _possibleConstructorReturn(this, (AnalyticsController.__proto__ || Object.getPrototypeOf(AnalyticsController)).apply(this, arguments));
}
_createClass(AnalyticsController, [{
key: 'appOpened',
value: function appOpened(req) {
var _this2 = this;
return Promise.resolve().then(function () {
return _this2.adapter.appOpened(req.body, req);
}).then(function (response) {
return { response: response || {} };
}).catch(function () {
return { response: {} };
});
}
}, {
key: 'trackEvent',
value: function trackEvent(req) {
var _this3 = this;
return Promise.resolve().then(function () {
return _this3.adapter.trackEvent(req.params.eventName, req.body, req);
}).then(function (response) {
return { response: response || {} };
}).catch(function () {
return { response: {} };
});
}
}, {
key: 'expectedAdapterType',
value: function expectedAdapterType() {
return _AnalyticsAdapter.AnalyticsAdapter;
}
}]);
return AnalyticsController;
}(_AdaptableController3.default);
exports.default = AnalyticsController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 1 1 9 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CacheController = exports.SubCache = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _AdaptableController2 = require('./AdaptableController');
var _AdaptableController3 = _interopRequireDefault(_AdaptableController2);
var _CacheAdapter = require('../Adapters/Cache/CacheAdapter');
var _CacheAdapter2 = _interopRequireDefault(_CacheAdapter);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var KEY_SEPARATOR_CHAR = ':';
function joinKeys() {
for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) {
keys[_key] = arguments[_key];
}
return keys.join(KEY_SEPARATOR_CHAR);
}
/**
* Prefix all calls to the cache via a prefix string, useful when grouping Cache by object type.
*
* eg "Role" or "Session"
*/
var SubCache = exports.SubCache = function () {
function SubCache(prefix, cacheController, ttl) {
_classCallCheck(this, SubCache);
this.prefix = prefix;
this.cache = cacheController;
this.ttl = ttl;
}
_createClass(SubCache, [{
key: 'get',
value: function get(key) {
var cacheKey = joinKeys(this.prefix, key);
return this.cache.get(cacheKey);
}
}, {
key: 'put',
value: function put(key, value, ttl) {
var cacheKey = joinKeys(this.prefix, key);
return this.cache.put(cacheKey, value, ttl);
}
}, {
key: 'del',
value: function del(key) {
var cacheKey = joinKeys(this.prefix, key);
return this.cache.del(cacheKey);
}
}, {
key: 'clear',
value: function clear() {
return this.cache.clear();
}
}]);
return SubCache;
}();
var CacheController = exports.CacheController = function (_AdaptableController) {
_inherits(CacheController, _AdaptableController);
function CacheController(adapter, appId) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
_classCallCheck(this, CacheController);
var _this = _possibleConstructorReturn(this, (CacheController.__proto__ || Object.getPrototypeOf(CacheController)).call(this, adapter, appId, options));
_this.role = new SubCache('role', _this);
_this.user = new SubCache('user', _this);
return _this;
}
_createClass(CacheController, [{
key: 'get',
value: function get(key) {
var cacheKey = joinKeys(this.appId, key);
return this.adapter.get(cacheKey).then(null, function () {
return Promise.resolve(null);
});
}
}, {
key: 'put',
value: function put(key, value, ttl) {
var cacheKey = joinKeys(this.appId, key);
return this.adapter.put(cacheKey, value, ttl);
}
}, {
key: 'del',
value: function del(key) {
var cacheKey = joinKeys(this.appId, key);
return this.adapter.del(cacheKey);
}
}, {
key: 'clear',
value: function clear() {
return this.adapter.clear();
}
}, {
key: 'expectedAdapterType',
value: function expectedAdapterType() {
return _CacheAdapter2.default;
}
}]);
return CacheController;
}(_AdaptableController3.default);
exports.default = CacheController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _node = require('parse/node'); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _intersect = require('intersect'); var _intersect2 = _interopRequireDefault(_intersect); var _deepcopy = require('deepcopy'); var _deepcopy2 = _interopRequireDefault(_deepcopy); var _logger = require('../logger'); var _logger2 = _interopRequireDefault(_logger); var _SchemaController = require('./SchemaController'); var SchemaController = _interopRequireWildcard(_SchemaController); function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // A database adapter that works with data exported from the hosted // Parse database. function addWriteACL(query, acl) { var newQuery = _lodash2.default.cloneDeep(query); //Can't be any existing '_wperm' query, we don't allow client queries on that, no need to $and newQuery._wperm = { "$in": [null].concat(_toConsumableArray(acl)) }; return newQuery; } function addReadACL(query, acl) { var newQuery = _lodash2.default.cloneDeep(query); //Can't be any existing '_rperm' query, we don't allow client queries on that, no need to $and newQuery._rperm = { "$in": [null, "*"].concat(_toConsumableArray(acl)) }; return newQuery; } // Transforms a REST API formatted ACL object to our two-field mongo format. var transformObjectACL = function transformObjectACL(_ref) { var ACL = _ref.ACL, result = _objectWithoutProperties(_ref, ['ACL']); if (!ACL) { return result; } result._wperm = []; result._rperm = []; for (var entry in ACL) { if (ACL[entry].read) { result._rperm.push(entry); } if (ACL[entry].write) { result._wperm.push(entry); } } return result; }; var specialQuerykeys = ['$and', '$or', '_rperm', '_wperm', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count']; var isSpecialQueryKey = function isSpecialQueryKey(key) { return specialQuerykeys.indexOf(key) >= 0; }; var validateQuery = function validateQuery(query) { if (query.ACL) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Cannot query on ACL.'); } if (query.$or) { if (query.$or instanceof Array) { query.$or.forEach(validateQuery); /* In MongoDB, $or queries which are not alone at the top level of the * query can not make efficient use of indexes due to a long standing * bug known as SERVER-13732. * * This block restructures queries in which $or is not the sole top * level element by moving all other top-level predicates inside every * subdocument of the $or predicate, allowing MongoDB's query planner * to make full use of the most relevant indexes. * * EG: {$or: [{a: 1}, {a: 2}], b: 2} * Becomes: {$or: [{a: 1, b: 2}, {a: 2, b: 2}]} * * https://jira.mongodb.org/browse/SERVER-13732 */ Object.keys(query).forEach(function (key) { var noCollisions = !query.$or.some(function (subq) { return subq.hasOwnProperty(key); }); if (key != '$or' && noCollisions) { query.$or.forEach(function (subquery) { subquery[key] = query[key]; }); delete query[key]; } }); } else { throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $or format - use an array value.'); } } if (query.$and) { if (query.$and instanceof Array) { query.$and.forEach(validateQuery); } else { throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $and format - use an array value.'); } } Object.keys(query).forEach(function (key) { if (query && query[key] && query[key].$regex) { if (typeof query[key].$options === 'string') { if (!query[key].$options.match(/^[imxs]+$/)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $options value for query: ' + query[key].$options); } } } if (!isSpecialQueryKey(key) && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, 'Invalid key name: ' + key); } }); }; function DatabaseController(adapter, schemaCache) { this.adapter = adapter; this.schemaCache = schemaCache; // We don't want a mutable this.schema, because then you could have // one request that uses different schemas for different parts of // it. Instead, use loadSchema to get a schema. this.schemaPromise = null; } DatabaseController.prototype.collectionExists = function (className) { return this.adapter.classExists(className); }; DatabaseController.prototype.purgeCollection = function (className) { var _this = this; return this.loadSchema().then(function (schemaController) { return schemaController.getOneSchema(className); }).then(function (schema) { return _this.adapter.deleteObjectsByQuery(className, schema, {}); }); }; DatabaseController.prototype.validateClassName = function (className) { if (!SchemaController.classNameIsValid(className)) { return Promise.reject(new _node.Parse.Error(_node.Parse.Error.INVALID_CLASS_NAME, 'invalid className: ' + className)); } return Promise.resolve(); }; // Returns a promise for a schemaController. DatabaseController.prototype.loadSchema = function () { var _this2 = this; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { clearCache: false }; if (!this.schemaPromise) { this.schemaPromise = SchemaController.load(this.adapter, this.schemaCache, options); this.schemaPromise.then(function () { return delete _this2.schemaPromise; }, function () { return delete _this2.schemaPromise; }); } return this.schemaPromise; }; // Returns a promise for the classname that is related to the given // classname through the key. // TODO: make this not in the DatabaseController interface DatabaseController.prototype.redirectClassNameForKey = function (className, key) { return this.loadSchema().then(function (schema) { var t = schema.getExpectedType(className, key); if (t && t.type == 'Relation') { return t.targetClass; } else { return className; } }); }; // Uses the schema to validate the object (REST API format). // Returns a promise that resolves to the new schema. // This does not update this.schema, because in a situation like a // batch request, that could confuse other users of the schema. DatabaseController.prototype.validateObject = function (className, object, query, _ref2) { var _this3 = this; var acl = _ref2.acl; var schema = void 0; var isMaster = acl === undefined; var aclGroup = acl || []; return this.loadSchema().then(function (s) { schema = s; if (isMaster) { return Promise.resolve(); } return _this3.canAddField(schema, className, object, aclGroup); }).then(function () { return schema.validateObject(className, object, query); }); }; // Filters out any data that shouldn't be on this REST-formatted object. var filterSensitiveData = function filterSensitiveData(isMaster, aclGroup, className, object) { if (className !== '_User') { return object; } object.password = object._hashed_password; delete object._hashed_password; delete object.sessionToken; if (isMaster) { return object; } delete object._email_verify_token; delete object._perishable_token; delete object._perishable_token_expires_at; delete object._tombstone; delete object._email_verify_token_expires_at; delete object._failed_login_count; delete object._account_lockout_expires_at; delete object._password_changed_at; if (aclGroup.indexOf(object.objectId) > -1) { return object; } delete object.authData; return object; }; // Runs an update on the database. // Returns a promise for an object with the new values for field // modifications that don't know their results ahead of time, like // 'increment'. // Options: // acl: a list of strings. If the object to be updated has an ACL, // one of the provided strings must provide the caller with // write permissions. var specialKeysForUpdate = ['_hashed_password', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count', '_perishable_token_expires_at', '_password_changed_at', '_password_history']; var isSpecialUpdateKey = function isSpecialUpdateKey(key) { return specialKeysForUpdate.indexOf(key) >= 0; }; DatabaseController.prototype.update = function (className, query, update) { var _this4 = this; var _ref3 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}, acl = _ref3.acl, many = _ref3.many, upsert = _ref3.upsert; var skipSanitization = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; var originalUpdate = update; // Make a copy of the object, so we don't mutate the incoming data. update = (0, _deepcopy2.default)(update); var isMaster = acl === undefined; var aclGroup = acl || []; return this.loadSchema().then(function (schemaController) { return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'update')).then(function () { return _this4.handleRelationUpdates(className, query.objectId, update); }).then(function () { if (!isMaster) { query = _this4.addPointerPermissions(schemaController, className, 'update', query, aclGroup); } if (!query) { return Promise.resolve(); } if (acl) { query = addWriteACL(query, acl); } validateQuery(query); return schemaController.getOneSchema(className, true).catch(function (error) { // If the schema doesn't exist, pretend it exists with no fields. This behaviour // will likely need revisiting. if (error === undefined) { return { fields: {} }; } throw error; }).then(function (schema) { Object.keys(update).forEach(function (fieldName) { if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, 'Invalid field name for update: ' + fieldName); } fieldName = fieldName.split('.')[0]; if (!SchemaController.fieldNameIsValid(fieldName) && !isSpecialUpdateKey(fieldName)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, 'Invalid field name for update: ' + fieldName); } }); for (var updateOperation in update) { if (Object.keys(updateOperation).some(function (innerKey) { return innerKey.includes('$') || innerKey.includes('.'); })) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters"); } } update = transformObjectACL(update); transformAuthData(className, update, schema); if (many) { return _this4.adapter.updateObjectsByQuery(className, schema, query, update); } else if (upsert) { return _this4.adapter.upsertOneObject(className, schema, query, update); } else { return _this4.adapter.findOneAndUpdate(className, schema, query, update); } }); }).then(function (result) { if (!result) { return Promise.reject(new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.')); } if (skipSanitization) { return Promise.resolve(result); } return sanitizeDatabaseResult(originalUpdate, result); }); }); }; function sanitizeDatabaseResult(originalObject, result) { var response = {}; if (!result) { return Promise.resolve(response); } Object.keys(originalObject).forEach(function (key) { var keyUpdate = originalObject[key]; // determine if that was an op if (keyUpdate && (typeof keyUpdate === 'undefined' ? 'undefined' : _typeof(keyUpdate)) === 'object' && keyUpdate.__op && ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1) { // only valid ops that produce an actionable result response[key] = result[key]; } }); return Promise.resolve(response); } // Processes relation-updating operations from a REST-format update. // Returns a promise that resolves successfully when these are // processed. // This mutates update. DatabaseController.prototype.handleRelationUpdates = function (className, objectId, update) { var _this5 = this; var pending = []; var deleteMe = []; objectId = update.objectId || objectId; var process = function process(op, key) { if (!op) { return; } if (op.__op == 'AddRelation') { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = op.objects[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var object = _step.value; pending.push(_this5.addRelation(key, className, objectId, object.objectId)); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } deleteMe.push(key); } if (op.__op == 'RemoveRelation') { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = op.objects[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _object = _step2.value; pending.push(_this5.removeRelation(key, className, objectId, _object.objectId)); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } deleteMe.push(key); } if (op.__op == 'Batch') { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = op.ops[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var x = _step3.value; process(x, key); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } }; for (var key in update) { process(update[key], key); } var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = deleteMe[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _key = _step4.value; delete update[_key]; } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } return Promise.all(pending); }; // Adds a relation. // Returns a promise that resolves successfully iff the add was successful. var relationSchema = { fields: { relatedId: { type: 'String' }, owningId: { type: 'String' } } }; DatabaseController.prototype.addRelation = function (key, fromClassName, fromId, toId) { var doc = { relatedId: toId, owningId: fromId }; return this.adapter.upsertOneObject('_Join:' + key + ':' + fromClassName, relationSchema, doc, doc); }; // Removes a relation. // Returns a promise that resolves successfully iff the remove was // successful. DatabaseController.prototype.removeRelation = function (key, fromClassName, fromId, toId) { var doc = { relatedId: toId, owningId: fromId }; return this.adapter.deleteObjectsByQuery('_Join:' + key + ':' + fromClassName, relationSchema, doc).catch(function (error) { // We don't care if they try to delete a non-existent relation. if (error.code == _node.Parse.Error.OBJECT_NOT_FOUND) { return; } throw error; }); }; // Removes objects matches this query from the database. // Returns a promise that resolves successfully iff the object was // deleted. // Options: // acl: a list of strings. If the object to be updated has an ACL, // one of the provided strings must provide the caller with // write permissions. DatabaseController.prototype.destroy = function (className, query) { var _this6 = this; var _ref4 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, acl = _ref4.acl; var isMaster = acl === undefined; var aclGroup = acl || []; return this.loadSchema().then(function (schemaController) { return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'delete')).then(function () { if (!isMaster) { query = _this6.addPointerPermissions(schemaController, className, 'delete', query, aclGroup); if (!query) { throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); } } // delete by query if (acl) { query = addWriteACL(query, acl); } validateQuery(query); return schemaController.getOneSchema(className).catch(function (error) { // If the schema doesn't exist, pretend it exists with no fields. This behaviour // will likely need revisiting. if (error === undefined) { return { fields: {} }; } throw error; }).then(function (parseFormatSchema) { return _this6.adapter.deleteObjectsByQuery(className, parseFormatSchema, query); }).catch(function (error) { // When deleting sessions while changing passwords, don't throw an error if they don't have any sessions. if (className === "_Session" && error.code === _node.Parse.Error.OBJECT_NOT_FOUND) { return Promise.resolve({}); } throw error; }); }); }); }; var flattenUpdateOperatorsForCreate = function flattenUpdateOperatorsForCreate(object) { for (var key in object) { if (object[key] && object[key].__op) { switch (object[key].__op) { case 'Increment': if (typeof object[key].amount !== 'number') { throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array'); } object[key] = object[key].amount; break; case 'Add': if (!(object[key].objects instanceof Array)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array'); } object[key] = object[key].objects; break; case 'AddUnique': if (!(object[key].objects instanceof Array)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array'); } object[key] = object[key].objects; break; case 'Remove': if (!(object[key].objects instanceof Array)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array'); } object[key] = []; break; case 'Delete': delete object[key]; break; default: throw new _node.Parse.Error(_node.Parse.Error.COMMAND_UNAVAILABLE, 'The ' + object[key].__op + ' operator is not supported yet.'); } } } }; var transformAuthData = function transformAuthData(className, object, schema) { if (object.authData && className === '_User') { Object.keys(object.authData).forEach(function (provider) { var providerData = object.authData[provider]; var fieldName = '_auth_data_' + provider; if (providerData == null) { object[fieldName] = { __op: 'Delete' }; } else { object[fieldName] = providerData; schema.fields[fieldName] = { type: 'Object' }; } }); delete object.authData; } }; // Inserts an object into the database. // Returns a promise that resolves successfully iff the object saved. DatabaseController.prototype.create = function (className, object) { var _this7 = this; var _ref5 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, acl = _ref5.acl; // Make a copy of the object, so we don't mutate the incoming data. var originalObject = object; object = transformObjectACL(object); object.createdAt = { iso: object.createdAt, __type: 'Date' }; object.updatedAt = { iso: object.updatedAt, __type: 'Date' }; var isMaster = acl === undefined; var aclGroup = acl || []; return this.validateClassName(className).then(function () { return _this7.loadSchema(); }).then(function (schemaController) { return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'create')).then(function () { return _this7.handleRelationUpdates(className, null, object); }).then(function () { return schemaController.enforceClassExists(className); }).then(function () { return schemaController.reloadData(); }).then(function () { return schemaController.getOneSchema(className, true); }).then(function (schema) { transformAuthData(className, object, schema); flattenUpdateOperatorsForCreate(object); return _this7.adapter.createObject(className, SchemaController.convertSchemaToAdapterSchema(schema), object); }).then(function (result) { return sanitizeDatabaseResult(originalObject, result.ops[0]); }); }); }; DatabaseController.prototype.canAddField = function (schema, className, object, aclGroup) { var classSchema = schema.data[className]; if (!classSchema) { return Promise.resolve(); } var fields = Object.keys(object); var schemaFields = Object.keys(classSchema); var newKeys = fields.filter(function (field) { return schemaFields.indexOf(field) < 0; }); if (newKeys.length > 0) { return schema.validatePermission(className, aclGroup, 'addField'); } return Promise.resolve(); }; // Won't delete collections in the system namespace // Returns a promise. DatabaseController.prototype.deleteEverything = function () { this.schemaPromise = null; return Promise.all([this.adapter.deleteAllClasses(), this.schemaCache.clear()]); }; // Returns a promise for a list of related ids given an owning id. // className here is the owning className. DatabaseController.prototype.relatedIds = function (className, key, owningId) { return this.adapter.find(joinTableName(className, key), relationSchema, { owningId: owningId }, {}).then(function (results) { return results.map(function (result) { return result.relatedId; }); }); }; // Returns a promise for a list of owning ids given some related ids. // className here is the owning className. DatabaseController.prototype.owningIds = function (className, key, relatedIds) { return this.adapter.find(joinTableName(className, key), relationSchema, { relatedId: { '$in': relatedIds } }, {}).then(function (results) { return results.map(function (result) { return result.owningId; }); }); }; // Modifies query so that it no longer has $in on relation fields, or // equal-to-pointer constraints on relation fields. // Returns a promise that resolves when query is mutated DatabaseController.prototype.reduceInRelation = function (className, query, schema) { var _this8 = this; // Search for an in-relation or equal-to-relation // Make it sequential for now, not sure of paralleization side effects if (query['$or']) { var ors = query['$or']; return Promise.all(ors.map(function (aQuery, index) { return _this8.reduceInRelation(className, aQuery, schema).then(function (aQuery) { query['$or'][index] = aQuery; }); })).then(function () { return Promise.resolve(query); }); } var promises = Object.keys(query).map(function (key) { if (query[key] && (query[key]['$in'] || query[key]['$ne'] || query[key]['$nin'] || query[key].__type == 'Pointer')) { var t = schema.getExpectedType(className, key); if (!t || t.type !== 'Relation') { return Promise.resolve(query); } // Build the list of queries var queries = Object.keys(query[key]).map(function (constraintKey) { var relatedIds = void 0; var isNegation = false; if (constraintKey === 'objectId') { relatedIds = [query[key].objectId]; } else if (constraintKey == '$in') { relatedIds = query[key]['$in'].map(function (r) { return r.objectId; }); } else if (constraintKey == '$nin') { isNegation = true; relatedIds = query[key]['$nin'].map(function (r) { return r.objectId; }); } else if (constraintKey == '$ne') { isNegation = true; relatedIds = [query[key]['$ne'].objectId]; } else { return; } return { isNegation: isNegation, relatedIds: relatedIds }; }); // remove the current queryKey as we don,t need it anymore delete query[key]; // execute each query independnently to build the list of // $in / $nin var _promises = queries.map(function (q) { if (!q) { return Promise.resolve(); } return _this8.owningIds(className, key, q.relatedIds).then(function (ids) { if (q.isNegation) { _this8.addNotInObjectIdsIds(ids, query); } else { _this8.addInObjectIdsIds(ids, query); } return Promise.resolve(); }); }); return Promise.all(_promises).then(function () { return Promise.resolve(); }); } return Promise.resolve(); }); return Promise.all(promises).then(function () { return Promise.resolve(query); }); }; // Modifies query so that it no longer has $relatedTo // Returns a promise that resolves when query is mutated DatabaseController.prototype.reduceRelationKeys = function (className, query) { var _this9 = this; if (query['$or']) { return Promise.all(query['$or'].map(function (aQuery) { return _this9.reduceRelationKeys(className, aQuery); })); } var relatedTo = query['$relatedTo']; if (relatedTo) { return this.relatedIds(relatedTo.object.className, relatedTo.key, relatedTo.object.objectId).then(function (ids) { delete query['$relatedTo']; _this9.addInObjectIdsIds(ids, query); return _this9.reduceRelationKeys(className, query); }); } }; DatabaseController.prototype.addInObjectIdsIds = function () { var ids = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var query = arguments[1]; var idsFromString = typeof query.objectId === 'string' ? [query.objectId] : null; var idsFromEq = query.objectId && query.objectId['$eq'] ? [query.objectId['$eq']] : null; var idsFromIn = query.objectId && query.objectId['$in'] ? query.objectId['$in'] : null; var allIds = [idsFromString, idsFromEq, idsFromIn, ids].filter(function (list) { return list !== null; }); var totalLength = allIds.reduce(function (memo, list) { return memo + list.length; }, 0); var idsIntersection = []; if (totalLength > 125) { idsIntersection = _intersect2.default.big(allIds); } else { idsIntersection = (0, _intersect2.default)(allIds); } // Need to make sure we don't clobber existing shorthand $eq constraints on objectId. if (!('objectId' in query)) { query.objectId = {}; } else if (typeof query.objectId === 'string') { query.objectId = { $eq: query.objectId }; } query.objectId['$in'] = idsIntersection; return query; }; DatabaseController.prototype.addNotInObjectIdsIds = function () { var ids = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var query = arguments[1]; var idsFromNin = query.objectId && query.objectId['$nin'] ? query.objectId['$nin'] : []; var allIds = [].concat(_toConsumableArray(idsFromNin), _toConsumableArray(ids)).filter(function (list) { return list !== null; }); // make a set and spread to remove duplicates allIds = [].concat(_toConsumableArray(new Set(allIds))); // Need to make sure we don't clobber existing shorthand $eq constraints on objectId. if (!('objectId' in query)) { query.objectId = {}; } else if (typeof query.objectId === 'string') { query.objectId = { $eq: query.objectId }; } query.objectId['$nin'] = allIds; return query; }; // Runs a query on the database. // Returns a promise that resolves to a list of items. // Options: // skip number of results to skip. // limit limit to this number of results. // sort an object where keys are the fields to sort by. // the value is +1 for ascending, -1 for descending. // count run a count instead of returning results. // acl restrict this operation with an ACL for the provided array // of user objectIds and roles. acl: null means no user. // when this field is not present, don't do anything regarding ACLs. // TODO: make userIds not needed here. The db adapter shouldn't know // anything about users, ideally. Then, improve the format of the ACL // arg to work like the others. DatabaseController.prototype.find = function (className, query) { var _this10 = this; var _ref6 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, skip = _ref6.skip, limit = _ref6.limit, acl = _ref6.acl, _ref6$sort = _ref6.sort, sort = _ref6$sort === undefined ? {} : _ref6$sort, count = _ref6.count, keys = _ref6.keys, op = _ref6.op; var isMaster = acl === undefined; var aclGroup = acl || []; op = op || (typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find'); var classExists = true; return this.loadSchema().then(function (schemaController) { //Allow volatile classes if querying with Master (for _PushStatus) //TODO: Move volatile classes concept into mongo adatper, postgres adapter shouldn't care //that api.parse.com breaks when _PushStatus exists in mongo. return schemaController.getOneSchema(className, isMaster).catch(function (error) { // Behaviour for non-existent classes is kinda weird on Parse.com. Probably doesn't matter too much. // For now, pretend the class exists but has no objects, if (error === undefined) { classExists = false; return { fields: {} }; } throw error; }).then(function (schema) { // Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt, // so duplicate that behaviour here. If both are specified, the corrent behaviour to match Parse.com is to // use the one that appears first in the sort list. if (sort._created_at) { sort.createdAt = sort._created_at; delete sort._created_at; } if (sort._updated_at) { sort.updatedAt = sort._updated_at; delete sort._updated_at; } Object.keys(sort).forEach(function (fieldName) { if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, 'Cannot sort by ' + fieldName); } if (!SchemaController.fieldNameIsValid(fieldName)) { throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, 'Invalid field name: ' + fieldName + '.'); } }); return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op)).then(function () { return _this10.reduceRelationKeys(className, query); }).then(function () { return _this10.reduceInRelation(className, query, schemaController); }).then(function () { if (!isMaster) { query = _this10.addPointerPermissions(schemaController, className, op, query, aclGroup); } if (!query) { if (op == 'get') { throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); } else { return []; } } if (!isMaster) { query = addReadACL(query, aclGroup); } validateQuery(query); if (count) { if (!classExists) { return 0; } else { return _this10.adapter.count(className, schema, query); } } else { if (!classExists) { return []; } else { return _this10.adapter.find(className, schema, query, { skip: skip, limit: limit, sort: sort, keys: keys }).then(function (objects) { return objects.map(function (object) { object = untransformObjectACL(object); return filterSensitiveData(isMaster, aclGroup, className, object); }); }); } } }); }); }); }; // Transforms a Database format ACL to a REST API format ACL var untransformObjectACL = function untransformObjectACL(_ref7) { var _rperm = _ref7._rperm, _wperm = _ref7._wperm, output = _objectWithoutProperties(_ref7, ['_rperm', '_wperm']); if (_rperm || _wperm) { output.ACL = {}; (_rperm || []).forEach(function (entry) { if (!output.ACL[entry]) { output.ACL[entry] = { read: true }; } else { output.ACL[entry]['read'] = true; } }); (_wperm || []).forEach(function (entry) { if (!output.ACL[entry]) { output.ACL[entry] = { write: true }; } else { output.ACL[entry]['write'] = true; } }); } return output; }; DatabaseController.prototype.deleteSchema = function (className) { var _this11 = this; return this.loadSchema(true).then(function (schemaController) { return schemaController.getOneSchema(className, true); }).catch(function (error) { if (error === undefined) { return { fields: {} }; } else { throw error; } }).then(function (schema) { return _this11.collectionExists(className).then(function () { return _this11.adapter.count(className, { fields: {} }); }).then(function (count) { if (count > 0) { throw new _node.Parse.Error(255, 'Class ' + className + ' is not empty, contains ' + count + ' objects, cannot drop schema.'); } return _this11.adapter.deleteClass(className); }).then(function (wasParseCollection) { if (wasParseCollection) { var relationFieldNames = Object.keys(schema.fields).filter(function (fieldName) { return schema.fields[fieldName].type === 'Relation'; }); return Promise.all(relationFieldNames.map(function (name) { return _this11.adapter.deleteClass(joinTableName(className, name)); })); } else { return Promise.resolve(); } }); }); }; DatabaseController.prototype.addPointerPermissions = function (schema, className, operation, query) { var aclGroup = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; // Check if class has public permission for operation // If the BaseCLP pass, let go through if (schema.testBaseCLP(className, aclGroup, operation)) { return query; } var perms = schema.perms[className]; var field = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields'; var userACL = aclGroup.filter(function (acl) { return acl.indexOf('role:') != 0 && acl != '*'; }); // the ACL should have exactly 1 user if (perms && perms[field] && perms[field].length > 0) { // No user set return undefined // If the length is > 1, that means we didn't dedup users correctly if (userACL.length != 1) { return; } var userId = userACL[0]; var userPointer = { "__type": "Pointer", "className": "_User", "objectId": userId }; var permFields = perms[field]; var ors = permFields.map(function (key) { var q = _defineProperty({}, key, userPointer); return { '$and': [q, query] }; }); if (ors.length > 1) { return { '$or': ors }; } return ors[0]; } else { return query; } }; // TODO: create indexes on first creation of a _User object. Otherwise it's impossible to // have a Parse app without it having a _User collection. DatabaseController.prototype.performInitialization = function () { var _this12 = this; var requiredUserFields = { fields: _extends({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._User) }; var requiredRoleFields = { fields: _extends({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._Role) }; var userClassPromise = this.loadSchema().then(function (schema) { return schema.enforceClassExists('_User'); }); var roleClassPromise = this.loadSchema().then(function (schema) { return schema.enforceClassExists('_Role'); }); var usernameUniqueness = userClassPromise.then(function () { return _this12.adapter.ensureUniqueness('_User', requiredUserFields, ['username']); }).catch(function (error) { _logger2.default.warn('Unable to ensure uniqueness for usernames: ', error); throw error; }); var emailUniqueness = userClassPromise.then(function () { return _this12.adapter.ensureUniqueness('_User', requiredUserFields, ['email']); }).catch(function (error) { _logger2.default.warn('Unable to ensure uniqueness for user email addresses: ', error); throw error; }); var roleUniqueness = roleClassPromise.then(function () { return _this12.adapter.ensureUniqueness('_Role', requiredRoleFields, ['name']); }).catch(function (error) { _logger2.default.warn('Unable to ensure uniqueness for role name: ', error); throw error; }); // Create tables for volatile classes var adapterInit = this.adapter.performInitialization({ VolatileClassesSchemas: SchemaController.VolatileClassesSchemas }); return Promise.all([usernameUniqueness, emailUniqueness, roleUniqueness, adapterInit]); }; function joinTableName(className, key) { return '_Join:' + key + ':' + className; } // Expose validateQuery for tests DatabaseController._validateQuery = validateQuery; module.exports = DatabaseController; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 1 1 1 6 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FilesController = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _cryptoUtils = require('../cryptoUtils');
var _AdaptableController2 = require('./AdaptableController');
var _AdaptableController3 = _interopRequireDefault(_AdaptableController2);
var _FilesAdapter = require('../Adapters/Files/FilesAdapter');
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _mime = require('mime');
var _mime2 = _interopRequireDefault(_mime);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // FilesController.js
var legacyFilesRegex = new RegExp("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}-.*");
var FilesController = exports.FilesController = function (_AdaptableController) {
_inherits(FilesController, _AdaptableController);
function FilesController() {
_classCallCheck(this, FilesController);
return _possibleConstructorReturn(this, (FilesController.__proto__ || Object.getPrototypeOf(FilesController)).apply(this, arguments));
}
_createClass(FilesController, [{
key: 'getFileData',
value: function getFileData(config, filename) {
return this.adapter.getFileData(filename);
}
}, {
key: 'createFile',
value: function createFile(config, filename, data, contentType) {
var extname = _path2.default.extname(filename);
var hasExtension = extname.length > 0;
if (!hasExtension && contentType && _mime2.default.extension(contentType)) {
filename = filename + '.' + _mime2.default.extension(contentType);
} else if (hasExtension && !contentType) {
contentType = _mime2.default.lookup(filename);
}
filename = (0, _cryptoUtils.randomHexString)(32) + '_' + filename;
var location = this.adapter.getFileLocation(config, filename);
return this.adapter.createFile(filename, data, contentType).then(function () {
return Promise.resolve({
url: location,
name: filename
});
});
}
}, {
key: 'deleteFile',
value: function deleteFile(config, filename) {
return this.adapter.deleteFile(filename);
}
/**
* Find file references in REST-format object and adds the url key
* with the current mount point and app id.
* Object may be a single object or list of REST-format objects.
*/
}, {
key: 'expandFilesInObject',
value: function expandFilesInObject(config, object) {
var _this2 = this;
if (object instanceof Array) {
object.map(function (obj) {
return _this2.expandFilesInObject(config, obj);
});
return;
}
if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) !== 'object') {
return;
}
for (var key in object) {
var fileObject = object[key];
if (fileObject && fileObject['__type'] === 'File') {
if (fileObject['url']) {
continue;
}
var filename = fileObject['name'];
// all filenames starting with "tfss-" should be from files.parsetfss.com
// all filenames starting with a "-" seperated UUID should be from files.parse.com
// all other filenames have been migrated or created from Parse Server
if (config.fileKey === undefined) {
fileObject['url'] = this.adapter.getFileLocation(config, filename);
} else {
if (filename.indexOf('tfss-') === 0) {
fileObject['url'] = 'http://files.parsetfss.com/' + config.fileKey + '/' + encodeURIComponent(filename);
} else if (legacyFilesRegex.test(filename)) {
fileObject['url'] = 'http://files.parse.com/' + config.fileKey + '/' + encodeURIComponent(filename);
} else {
fileObject['url'] = this.adapter.getFileLocation(config, filename);
}
}
}
}
}
}, {
key: 'expectedAdapterType',
value: function expectedAdapterType() {
return _FilesAdapter.FilesAdapter;
}
}, {
key: 'getFileStream',
value: function getFileStream(config, filename) {
return this.adapter.getFileStream(filename);
}
}]);
return FilesController;
}(_AdaptableController3.default);
exports.default = FilesController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | 1 1 1 15 1 1 1 1 1 1 1 45 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.HooksController = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** weak */
var _triggers = require("../triggers");
var triggers = _interopRequireWildcard(_triggers);
var _node = require("parse/node");
var Parse = _interopRequireWildcard(_node);
var _request = require("request");
var request = _interopRequireWildcard(_request);
var _logger = require("../logger");
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; Eif (obj != null) { for (var key in obj) { Eif (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var DefaultHooksCollectionName = "_Hooks";
var HooksController = exports.HooksController = function () {
function HooksController(applicationId, databaseController, webhookKey) {
_classCallCheck(this, HooksController);
this._applicationId = applicationId;
this._webhookKey = webhookKey;
this.database = databaseController;
}
_createClass(HooksController, [{
key: "load",
value: function load() {
var _this = this;
return this._getHooks().then(function (hooks) {
hooks = hooks || [];
hooks.forEach(function (hook) {
_this.addHookToTriggers(hook);
});
});
}
}, {
key: "getFunction",
value: function getFunction(functionName) {
return this._getHooks({ functionName: functionName }, 1).then(function (results) {
return results[0];
});
}
}, {
key: "getFunctions",
value: function getFunctions() {
return this._getHooks({ functionName: { $exists: true } });
}
}, {
key: "getTrigger",
value: function getTrigger(className, triggerName) {
return this._getHooks({ className: className, triggerName: triggerName }, 1).then(function (results) {
return results[0];
});
}
}, {
key: "getTriggers",
value: function getTriggers() {
return this._getHooks({ className: { $exists: true }, triggerName: { $exists: true } });
}
}, {
key: "deleteFunction",
value: function deleteFunction(functionName) {
triggers.removeFunction(functionName, this._applicationId);
return this._removeHooks({ functionName: functionName });
}
}, {
key: "deleteTrigger",
value: function deleteTrigger(className, triggerName) {
triggers.removeTrigger(triggerName, className, this._applicationId);
return this._removeHooks({ className: className, triggerName: triggerName });
}
}, {
key: "_getHooks",
value: function _getHooks() {
var query = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this.database.find(DefaultHooksCollectionName, query).then(function (results) {
return results.map(function (result) {
delete result.objectId;
return result;
});
});
}
}, {
key: "_removeHooks",
value: function _removeHooks(query) {
return this.database.destroy(DefaultHooksCollectionName, query).then(function () {
return Promise.resolve({});
});
}
}, {
key: "saveHook",
value: function saveHook(hook) {
var query;
if (hook.functionName && hook.url) {
query = { functionName: hook.functionName };
} else if (hook.triggerName && hook.className && hook.url) {
query = { className: hook.className, triggerName: hook.triggerName };
} else {
throw new Parse.Error(143, "invalid hook declaration");
}
return this.database.update(DefaultHooksCollectionName, query, hook, { upsert: true }).then(function () {
return Promise.resolve(hook);
});
}
}, {
key: "addHookToTriggers",
value: function addHookToTriggers(hook) {
var wrappedFunction = wrapToHTTPRequest(hook, this._webhookKey);
wrappedFunction.url = hook.url;
if (hook.className) {
triggers.addTrigger(hook.triggerName, hook.className, wrappedFunction, this._applicationId);
} else {
triggers.addFunction(hook.functionName, wrappedFunction, null, this._applicationId);
}
}
}, {
key: "addHook",
value: function addHook(hook) {
this.addHookToTriggers(hook);
return this.saveHook(hook);
}
}, {
key: "createOrUpdateHook",
value: function createOrUpdateHook(aHook) {
var hook;
if (aHook && aHook.functionName && aHook.url) {
hook = {};
hook.functionName = aHook.functionName;
hook.url = aHook.url;
} else if (aHook && aHook.className && aHook.url && aHook.triggerName && triggers.Types[aHook.triggerName]) {
hook = {};
hook.className = aHook.className;
hook.url = aHook.url;
hook.triggerName = aHook.triggerName;
} else {
throw new Parse.Error(143, "invalid hook declaration");
}
return this.addHook(hook);
}
}, {
key: "createHook",
value: function createHook(aHook) {
var _this2 = this;
if (aHook.functionName) {
return this.getFunction(aHook.functionName).then(function (result) {
if (result) {
throw new Parse.Error(143, "function name: " + aHook.functionName + " already exits");
} else {
return _this2.createOrUpdateHook(aHook);
}
});
} else if (aHook.className && aHook.triggerName) {
return this.getTrigger(aHook.className, aHook.triggerName).then(function (result) {
if (result) {
throw new Parse.Error(143, "class " + aHook.className + " already has trigger " + aHook.triggerName);
}
return _this2.createOrUpdateHook(aHook);
});
}
throw new Parse.Error(143, "invalid hook declaration");
}
}, {
key: "updateHook",
value: function updateHook(aHook) {
var _this3 = this;
if (aHook.functionName) {
return this.getFunction(aHook.functionName).then(function (result) {
if (result) {
return _this3.createOrUpdateHook(aHook);
}
throw new Parse.Error(143, "no function named: " + aHook.functionName + " is defined");
});
} else if (aHook.className && aHook.triggerName) {
return this.getTrigger(aHook.className, aHook.triggerName).then(function (result) {
if (result) {
return _this3.createOrUpdateHook(aHook);
}
throw new Parse.Error(143, "class " + aHook.className + " does not exist");
});
}
throw new Parse.Error(143, "invalid hook declaration");
}
}]);
return HooksController;
}();
function wrapToHTTPRequest(hook, key) {
return function (req, res) {
var jsonBody = {};
for (var i in req) {
jsonBody[i] = req[i];
}
if (req.object) {
jsonBody.object = req.object.toJSON();
jsonBody.object.className = req.object.className;
}
if (req.original) {
jsonBody.original = req.original.toJSON();
jsonBody.original.className = req.original.className;
}
var jsonRequest = {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jsonBody)
};
if (key) {
jsonRequest.headers['X-Parse-Webhook-Key'] = key;
} else {
_logger.logger.warn('Making outgoing webhook request without webhookKey being set!');
}
request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
var result;
if (body) {
if (typeof body === "string") {
try {
body = JSON.parse(body);
} catch (e) {
err = { error: "Malformed response", code: -1 };
}
}
if (!err) {
result = body.success;
err = body.error;
}
}
if (err) {
return res.error(err);
} else if (hook.triggerName === 'beforeSave') {
if ((typeof result === "undefined" ? "undefined" : _typeof(result)) === 'object') {
delete result.createdAt;
delete result.updatedAt;
}
return res.success({ object: result });
} else {
return res.success(result);
}
});
};
}
exports.default = HooksController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1 1 4 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LiveQueryController = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _ParseCloudCodePublisher = require('../LiveQuery/ParseCloudCodePublisher');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var LiveQueryController = exports.LiveQueryController = function () {
function LiveQueryController(config) {
_classCallCheck(this, LiveQueryController);
// If config is empty, we just assume no classs needs to be registered as LiveQuery
if (!config || !config.classNames) {
this.classNames = new Set();
} else if (config.classNames instanceof Array) {
this.classNames = new Set(config.classNames);
} else {
throw 'liveQuery.classes should be an array of string';
}
this.liveQueryPublisher = new _ParseCloudCodePublisher.ParseCloudCodePublisher(config);
}
_createClass(LiveQueryController, [{
key: 'onAfterSave',
value: function onAfterSave(className, currentObject, originalObject) {
if (!this.hasLiveQuery(className)) {
return;
}
var req = this._makePublisherRequest(currentObject, originalObject);
this.liveQueryPublisher.onCloudCodeAfterSave(req);
}
}, {
key: 'onAfterDelete',
value: function onAfterDelete(className, currentObject, originalObject) {
if (!this.hasLiveQuery(className)) {
return;
}
var req = this._makePublisherRequest(currentObject, originalObject);
this.liveQueryPublisher.onCloudCodeAfterDelete(req);
}
}, {
key: 'hasLiveQuery',
value: function hasLiveQuery(className) {
return this.classNames.has(className);
}
}, {
key: '_makePublisherRequest',
value: function _makePublisherRequest(currentObject, originalObject) {
var req = {
object: currentObject
};
if (currentObject) {
req.original = originalObject;
}
return req;
}
}]);
return LiveQueryController;
}();
exports.default = LiveQueryController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | 1 1 14 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LoggerController = exports.LogOrder = exports.LogLevel = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _node = require('parse/node');
var _AdaptableController2 = require('./AdaptableController');
var _AdaptableController3 = _interopRequireDefault(_AdaptableController2);
var _LoggerAdapter = require('../Adapters/Logger/LoggerAdapter');
var _url = require('url');
var _url2 = _interopRequireDefault(_url);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { Iif (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { Iif (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
var LOG_STRING_TRUNCATE_LENGTH = 1000;
var truncationMarker = '... (truncated)';
var LogLevel = exports.LogLevel = {
INFO: 'info',
ERROR: 'error'
};
var LogOrder = exports.LogOrder = {
DESCENDING: 'desc',
ASCENDING: 'asc'
};
var LoggerController = exports.LoggerController = function (_AdaptableController) {
_inherits(LoggerController, _AdaptableController);
function LoggerController() {
_classCallCheck(this, LoggerController);
return _possibleConstructorReturn(this, (LoggerController.__proto__ || Object.getPrototypeOf(LoggerController)).apply(this, arguments));
}
_createClass(LoggerController, [{
key: 'maskSensitiveUrl',
value: function maskSensitiveUrl(urlString) {
var password = _url2.default.parse(urlString, true).query.password;
if (password) {
urlString = urlString.replace('password=' + password, 'password=********');
}
return urlString;
}
}, {
key: 'maskSensitive',
value: function maskSensitive(argArray) {
var _this2 = this;
return argArray.map(function (e) {
Iif (!e) {
return e;
}
if (typeof e === 'string') {
return e.replace(/(password".?:.?")[^"]*"/g, '$1********"');
}
// else it is an object...
// check the url
Iif (e.url) {
// for strings
if (typeof e.url === 'string') {
e.url = _this2.maskSensitiveUrl(e.url);
} else if (Array.isArray(e.url)) {
// for strings in array
e.url = e.url.map(function (item) {
if (typeof item === 'string') {
return _this2.maskSensitiveUrl(item);
}
return item;
});
}
}
Iif (e.body) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(e.body)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var key = _step.value;
if (key === 'password') {
e.body[key] = '********';
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
return e;
});
}
}, {
key: 'log',
value: function log(level, args) {
// make the passed in arguments object an array with the spread operator
args = this.maskSensitive([].concat(_toConsumableArray(args)));
args = [].concat(level, args);
this.adapter.log.apply(this.adapter, args);
}
}, {
key: 'info',
value: function info() {
return this.log('info', arguments);
}
}, {
key: 'error',
value: function error() {
return this.log('error', arguments);
}
}, {
key: 'warn',
value: function warn() {
return this.log('warn', arguments);
}
}, {
key: 'verbose',
value: function verbose() {
return this.log('verbose', arguments);
}
}, {
key: 'debug',
value: function debug() {
return this.log('debug', arguments);
}
}, {
key: 'silly',
value: function silly() {
return this.log('silly', arguments);
}
// check that date input is valid
}, {
key: 'truncateLogMessage',
value: function truncateLogMessage(string) {
if (string && string.length > LOG_STRING_TRUNCATE_LENGTH) {
var truncated = string.substring(0, LOG_STRING_TRUNCATE_LENGTH) + truncationMarker;
return truncated;
}
return string;
}
}, {
key: 'getLogs',
// Returns a promise for a {response} object.
// query params:
// level (optional) Level of logging you want to query for (info || error)
// from (optional) Start time for the search. Defaults to 1 week ago.
// until (optional) End time for the search. Defaults to current time.
// order (optional) Direction of results returned, either “asc” or “desc”. Defaults to “desc”.
// size (optional) Number of rows returned by search. Defaults to 10
value: function getLogs() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (!this.adapter) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Logger adapter is not available');
}
if (typeof this.adapter.query !== 'function') {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Querying logs is not supported with this adapter');
}
options = LoggerController.parseOptions(options);
return this.adapter.query(options);
}
}, {
key: 'expectedAdapterType',
value: function expectedAdapterType() {
return _LoggerAdapter.LoggerAdapter;
}
}], [{
key: 'validDateTime',
value: function validDateTime(date) {
if (!date) {
return null;
}
date = new Date(date);
if (!isNaN(date.getTime())) {
return date;
}
return null;
}
}, {
key: 'parseOptions',
value: function parseOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var from = LoggerController.validDateTime(options.from) || new Date(Date.now() - 7 * MILLISECONDS_IN_A_DAY);
var until = LoggerController.validDateTime(options.until) || new Date();
var size = Number(options.size) || 10;
var order = options.order || LogOrder.DESCENDING;
var level = options.level || LogLevel.INFO;
return {
from: from,
until: until,
size: size,
order: order,
level: level
};
}
}]);
return LoggerController;
}(_AdaptableController3.default);
exports.default = LoggerController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 1 1 2 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PushController = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _node = require('parse/node');
var _deepcopy = require('deepcopy');
var _deepcopy2 = _interopRequireDefault(_deepcopy);
var _RestQuery = require('../RestQuery');
var _RestQuery2 = _interopRequireDefault(_RestQuery);
var _RestWrite = require('../RestWrite');
var _RestWrite2 = _interopRequireDefault(_RestWrite);
var _Auth = require('../Auth');
var _StatusHandler = require('../StatusHandler');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PushController = exports.PushController = function () {
function PushController() {
_classCallCheck(this, PushController);
}
_createClass(PushController, [{
key: 'sendPush',
value: function sendPush() {
var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var where = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var config = arguments[2];
var auth = arguments[3];
var onPushStatusSaved = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : function () {};
if (!config.hasPushSupport) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Missing push configuration');
}
// Replace the expiration_time with a valid Unix epoch milliseconds time
body['expiration_time'] = PushController.getExpirationTime(body);
// TODO: If the req can pass the checking, we return immediately instead of waiting
// pushes to be sent. We probably change this behaviour in the future.
var badgeUpdate = function badgeUpdate() {
return Promise.resolve();
};
if (body.data && body.data.badge) {
var badge = body.data.badge;
var restUpdate = {};
if (typeof badge == 'string' && badge.toLowerCase() === 'increment') {
restUpdate = { badge: { __op: 'Increment', amount: 1 } };
} else if (Number(badge)) {
restUpdate = { badge: badge };
} else {
throw "Invalid value for badge, expected number or 'Increment'";
}
var updateWhere = (0, _deepcopy2.default)(where);
badgeUpdate = function badgeUpdate() {
updateWhere.deviceType = 'ios';
// Build a real RestQuery so we can use it in RestWrite
var restQuery = new _RestQuery2.default(config, (0, _Auth.master)(config), '_Installation', updateWhere);
return restQuery.buildRestWhere().then(function () {
var write = new _RestWrite2.default(config, (0, _Auth.master)(config), '_Installation', restQuery.restWhere, restUpdate);
write.runOptions.many = true;
return write.execute();
});
};
}
var pushStatus = (0, _StatusHandler.pushStatusHandler)(config);
return Promise.resolve().then(function () {
return pushStatus.setInitial(body, where);
}).then(function () {
onPushStatusSaved(pushStatus.objectId);
return badgeUpdate();
}).then(function () {
return config.pushControllerQueue.enqueue(body, where, config, auth, pushStatus);
}).catch(function (err) {
return pushStatus.fail(err).then(function () {
throw err;
});
});
}
/**
* Get expiration time from the request body.
* @param {Object} request A request object
* @returns {Number|undefined} The expiration time if it exists in the request
*/
}], [{
key: 'getExpirationTime',
value: function getExpirationTime() {
var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var hasExpirationTime = !!body['expiration_time'];
if (!hasExpirationTime) {
return;
}
var expirationTimeParam = body['expiration_time'];
var expirationTime;
if (typeof expirationTimeParam === 'number') {
expirationTime = new Date(expirationTimeParam * 1000);
} else if (typeof expirationTimeParam === 'string') {
expirationTime = new Date(expirationTimeParam);
} else {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, body['expiration_time'] + ' is not valid time.');
}
// Check expirationTime is valid or not, if it is not valid, expirationTime is NaN
if (!isFinite(expirationTime)) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, body['expiration_time'] + ' is not valid time.');
}
return expirationTime.valueOf();
}
}]);
return PushController;
}();
exports.default = PushController;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1 6 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _cryptoUtils = require("../cryptoUtils");
var _defaults = require("../defaults");
var _defaults2 = _interopRequireDefault(_defaults);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var MAIN_SCHEMA = "__MAIN_SCHEMA";
var SCHEMA_CACHE_PREFIX = "__SCHEMA";
var ALL_KEYS = "__ALL_KEYS";
var SchemaCache = function () {
function SchemaCache(cacheController) {
var ttl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _defaults2.default.schemaCacheTTL;
var singleCache = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
_classCallCheck(this, SchemaCache);
this.ttl = ttl;
if (typeof ttl == 'string') {
this.ttl = parseInt(ttl);
}
this.cache = cacheController;
this.prefix = SCHEMA_CACHE_PREFIX;
if (!singleCache) {
this.prefix += (0, _cryptoUtils.randomString)(20);
}
}
_createClass(SchemaCache, [{
key: "put",
value: function put(key, value) {
var _this = this;
return this.cache.get(this.prefix + ALL_KEYS).then(function (allKeys) {
allKeys = allKeys || {};
allKeys[key] = true;
return Promise.all([_this.cache.put(_this.prefix + ALL_KEYS, allKeys, _this.ttl), _this.cache.put(key, value, _this.ttl)]);
});
}
}, {
key: "getAllClasses",
value: function getAllClasses() {
if (!this.ttl) {
return Promise.resolve(null);
}
return this.cache.get(this.prefix + MAIN_SCHEMA);
}
}, {
key: "setAllClasses",
value: function setAllClasses(schema) {
if (!this.ttl) {
return Promise.resolve(null);
}
return this.put(this.prefix + MAIN_SCHEMA, schema);
}
}, {
key: "setOneSchema",
value: function setOneSchema(className, schema) {
if (!this.ttl) {
return Promise.resolve(null);
}
return this.put(this.prefix + className, schema);
}
}, {
key: "getOneSchema",
value: function getOneSchema(className) {
var _this2 = this;
if (!this.ttl) {
return Promise.resolve(null);
}
return this.cache.get(this.prefix + className).then(function (schema) {
if (schema) {
return Promise.resolve(schema);
}
return _this2.cache.get(_this2.prefix + MAIN_SCHEMA).then(function (cachedSchemas) {
cachedSchemas = cachedSchemas || [];
schema = cachedSchemas.find(function (cachedSchema) {
return cachedSchema.className === className;
});
if (schema) {
return Promise.resolve(schema);
}
return Promise.resolve(null);
});
});
}
}, {
key: "clear",
value: function clear() {
var _this3 = this;
// That clears all caches...
return this.cache.get(this.prefix + ALL_KEYS).then(function (allKeys) {
if (!allKeys) {
return;
}
var promises = Object.keys(allKeys).map(function (key) {
return _this3.cache.del(key);
});
return Promise.all(promises);
});
}
}]);
return SchemaCache;
}();
exports.default = SchemaCache;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | 1 1 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 1 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
// This class handles schema validation, persistence, and modification.
//
// Each individual Schema object should be immutable. The helpers to
// do things with the Schema just return a new schema when the schema
// is changed.
//
// The canonical place to store this Schema is in the database itself,
// in a _SCHEMA collection. This is not the right way to do it for an
// open source framework, but it's backward compatible, so we're
// keeping it this way for now.
//
// In API-handling code, you should only use the Schema class via the
// DatabaseController. This will let us replace the schema logic for
// different databases.
// TODO: hide all schema logic inside the database adapter.
var Parse = require('parse/node').Parse;
var defaultColumns = Object.freeze({
// Contain the default columns for every parse object type (except _Join collection)
_Default: {
"objectId": { type: 'String' },
"createdAt": { type: 'Date' },
"updatedAt": { type: 'Date' },
"ACL": { type: 'ACL' }
},
// The additional default columns for the _User collection (in addition to DefaultCols)
_User: {
"username": { type: 'String' },
"password": { type: 'String' },
"email": { type: 'String' },
"emailVerified": { type: 'Boolean' },
"authData": { type: 'Object' }
},
// The additional default columns for the _Installation collection (in addition to DefaultCols)
_Installation: {
"installationId": { type: 'String' },
"deviceToken": { type: 'String' },
"channels": { type: 'Array' },
"deviceType": { type: 'String' },
"pushType": { type: 'String' },
"GCMSenderId": { type: 'String' },
"timeZone": { type: 'String' },
"localeIdentifier": { type: 'String' },
"badge": { type: 'Number' },
"appVersion": { type: 'String' },
"appName": { type: 'String' },
"appIdentifier": { type: 'String' },
"parseVersion": { type: 'String' }
},
// The additional default columns for the _Role collection (in addition to DefaultCols)
_Role: {
"name": { type: 'String' },
"users": { type: 'Relation', targetClass: '_User' },
"roles": { type: 'Relation', targetClass: '_Role' }
},
// The additional default columns for the _Session collection (in addition to DefaultCols)
_Session: {
"restricted": { type: 'Boolean' },
"user": { type: 'Pointer', targetClass: '_User' },
"installationId": { type: 'String' },
"sessionToken": { type: 'String' },
"expiresAt": { type: 'Date' },
"createdWith": { type: 'Object' }
},
_Product: {
"productIdentifier": { type: 'String' },
"download": { type: 'File' },
"downloadName": { type: 'String' },
"icon": { type: 'File' },
"order": { type: 'Number' },
"title": { type: 'String' },
"subtitle": { type: 'String' }
},
_PushStatus: {
"pushTime": { type: 'String' },
"source": { type: 'String' }, // rest or webui
"query": { type: 'String' }, // the stringified JSON query
"payload": { type: 'String' }, // the stringified JSON payload,
"title": { type: 'String' },
"expiry": { type: 'Number' },
"status": { type: 'String' },
"numSent": { type: 'Number' },
"numFailed": { type: 'Number' },
"pushHash": { type: 'String' },
"errorMessage": { type: 'Object' },
"sentPerType": { type: 'Object' },
"failedPerType": { type: 'Object' },
"count": { type: 'Number' }
},
_JobStatus: {
"jobName": { type: 'String' },
"source": { type: 'String' },
"status": { type: 'String' },
"message": { type: 'String' },
"params": { type: 'Object' }, // params received when calling the job
"finishedAt": { type: 'Date' }
},
_Hooks: {
"functionName": { type: 'String' },
"className": { type: 'String' },
"triggerName": { type: 'String' },
"url": { type: 'String' }
},
_GlobalConfig: {
"objectId": { type: 'String' },
"params": { type: 'Object' }
}
});
var requiredColumns = Object.freeze({
_Product: ["productIdentifier", "icon", "order", "title", "subtitle"],
_Role: ["name", "ACL"]
});
var systemClasses = Object.freeze(['_User', '_Installation', '_Role', '_Session', '_Product', '_PushStatus', '_JobStatus']);
var volatileClasses = Object.freeze(['_JobStatus', '_PushStatus', '_Hooks', '_GlobalConfig']);
// 10 alpha numberic chars + uppercase
var userIdRegex = /^[a-zA-Z0-9]{10}$/;
// Anything that start with role
var roleRegex = /^role:.*/;
// * permission
var publicRegex = /^\*$/;
var requireAuthenticationRegex = /^requiresAuthentication$/;
var permissionKeyRegex = Object.freeze([userIdRegex, roleRegex, publicRegex, requireAuthenticationRegex]);
function verifyPermissionKey(key) {
var result = permissionKeyRegex.reduce(function (isGood, regEx) {
isGood = isGood || key.match(regEx) != null;
return isGood;
}, false);
if (!result) {
throw new Parse.Error(Parse.Error.INVALID_JSON, '\'' + key + '\' is not a valid key for class level permissions');
}
}
var CLPValidKeys = Object.freeze(['find', 'get', 'create', 'update', 'delete', 'addField', 'readUserFields', 'writeUserFields']);
function validateCLP(perms, fields) {
if (!perms) {
return;
}
Object.keys(perms).forEach(function (operation) {
if (CLPValidKeys.indexOf(operation) == -1) {
throw new Parse.Error(Parse.Error.INVALID_JSON, operation + ' is not a valid operation for class level permissions');
}
if (operation === 'readUserFields' || operation === 'writeUserFields') {
if (!Array.isArray(perms[operation])) {
throw new Parse.Error(Parse.Error.INVALID_JSON, '\'' + perms[operation] + '\' is not a valid value for class level permissions ' + operation);
} else {
perms[operation].forEach(function (key) {
if (!fields[key] || fields[key].type != 'Pointer' || fields[key].targetClass != '_User') {
throw new Parse.Error(Parse.Error.INVALID_JSON, '\'' + key + '\' is not a valid column for class level pointer permissions ' + operation);
}
});
}
return;
}
Object.keys(perms[operation]).forEach(function (key) {
verifyPermissionKey(key);
var perm = perms[operation][key];
if (perm !== true) {
throw new Parse.Error(Parse.Error.INVALID_JSON, '\'' + perm + '\' is not a valid value for class level permissions ' + operation + ':' + key + ':' + perm);
}
});
});
}
var joinClassRegex = /^_Join:[A-Za-z0-9_]+:[A-Za-z0-9_]+/;
var classAndFieldRegex = /^[A-Za-z][A-Za-z0-9_]*$/;
function classNameIsValid(className) {
// Valid classes must:
return (
// Be one of _User, _Installation, _Role, _Session OR
systemClasses.indexOf(className) > -1 ||
// Be a join table OR
joinClassRegex.test(className) ||
// Include only alpha-numeric and underscores, and not start with an underscore or number
fieldNameIsValid(className)
);
}
// Valid fields must be alpha-numeric, and not start with an underscore or number
function fieldNameIsValid(fieldName) {
return classAndFieldRegex.test(fieldName);
}
// Checks that it's not trying to clobber one of the default fields of the class.
function fieldNameIsValidForClass(fieldName, className) {
if (!fieldNameIsValid(fieldName)) {
return false;
}
if (defaultColumns._Default[fieldName]) {
return false;
}
if (defaultColumns[className] && defaultColumns[className][fieldName]) {
return false;
}
return true;
}
function invalidClassNameMessage(className) {
return 'Invalid classname: ' + className + ', classnames can only have alphanumeric characters and _, and must start with an alpha character ';
}
var invalidJsonError = new Parse.Error(Parse.Error.INVALID_JSON, "invalid JSON");
var validNonRelationOrPointerTypes = ['Number', 'String', 'Boolean', 'Date', 'Object', 'Array', 'GeoPoint', 'File'];
// Returns an error suitable for throwing if the type is invalid
var fieldTypeIsInvalid = function fieldTypeIsInvalid(_ref) {
var type = _ref.type,
targetClass = _ref.targetClass;
if (['Pointer', 'Relation'].indexOf(type) >= 0) {
if (!targetClass) {
return new Parse.Error(135, 'type ' + type + ' needs a class name');
} else if (typeof targetClass !== 'string') {
return invalidJsonError;
} else if (!classNameIsValid(targetClass)) {
return new Parse.Error(Parse.Error.INVALID_CLASS_NAME, invalidClassNameMessage(targetClass));
} else {
return undefined;
}
}
if (typeof type !== 'string') {
return invalidJsonError;
}
if (validNonRelationOrPointerTypes.indexOf(type) < 0) {
return new Parse.Error(Parse.Error.INCORRECT_TYPE, 'invalid field type: ' + type);
}
return undefined;
};
var convertSchemaToAdapterSchema = function convertSchemaToAdapterSchema(schema) {
schema = injectDefaultSchema(schema);
delete schema.fields.ACL;
schema.fields._rperm = { type: 'Array' };
schema.fields._wperm = { type: 'Array' };
Iif (schema.className === '_User') {
delete schema.fields.password;
schema.fields._hashed_password = { type: 'String' };
}
return schema;
};
var convertAdapterSchemaToParseSchema = function convertAdapterSchemaToParseSchema(_ref2) {
var schema = _objectWithoutProperties(_ref2, []);
delete schema.fields._rperm;
delete schema.fields._wperm;
schema.fields.ACL = { type: 'ACL' };
if (schema.className === '_User') {
delete schema.fields.authData; //Auth data is implicit
delete schema.fields._hashed_password;
schema.fields.password = { type: 'String' };
}
return schema;
};
var injectDefaultSchema = function injectDefaultSchema(_ref3) {
var className = _ref3.className,
fields = _ref3.fields,
classLevelPermissions = _ref3.classLevelPermissions;
return {
className: className,
fields: _extends({}, defaultColumns._Default, defaultColumns[className] || {}, fields),
classLevelPermissions: classLevelPermissions
};
};
var _HooksSchema = { className: "_Hooks", fields: defaultColumns._Hooks };
var _GlobalConfigSchema = { className: "_GlobalConfig", fields: defaultColumns._GlobalConfig };
var _PushStatusSchema = convertSchemaToAdapterSchema(injectDefaultSchema({
className: "_PushStatus",
fields: {},
classLevelPermissions: {}
}));
var _JobStatusSchema = convertSchemaToAdapterSchema(injectDefaultSchema({
className: "_JobStatus",
fields: {},
classLevelPermissions: {}
}));
var VolatileClassesSchemas = [_HooksSchema, _JobStatusSchema, _PushStatusSchema, _GlobalConfigSchema];
var dbTypeMatchesObjectType = function dbTypeMatchesObjectType(dbType, objectType) {
if (dbType.type !== objectType.type) return false;
if (dbType.targetClass !== objectType.targetClass) return false;
if (dbType === objectType.type) return true;
if (dbType.type === objectType.type) return true;
return false;
};
var typeToString = function typeToString(type) {
if (type.targetClass) {
return type.type + '<' + type.targetClass + '>';
}
return '' + (type.type || type);
};
// Stores the entire schema of the app in a weird hybrid format somewhere between
// the mongo format and the Parse format. Soon, this will all be Parse format.
var SchemaController = function () {
function SchemaController(databaseAdapter, schemaCache) {
_classCallCheck(this, SchemaController);
this._dbAdapter = databaseAdapter;
this._cache = schemaCache;
// this.data[className][fieldName] tells you the type of that field, in mongo format
this.data = {};
// this.perms[className][operation] tells you the acl-style permissions
this.perms = {};
}
_createClass(SchemaController, [{
key: 'reloadData',
value: function reloadData() {
var _this = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { clearCache: false };
var promise = Promise.resolve();
if (options.clearCache) {
promise = promise.then(function () {
return _this._cache.clear();
});
}
if (this.reloadDataPromise && !options.clearCache) {
return this.reloadDataPromise;
}
this.reloadDataPromise = promise.then(function () {
return _this.getAllClasses(options);
}).then(function (allSchemas) {
var data = {};
var perms = {};
allSchemas.forEach(function (schema) {
data[schema.className] = injectDefaultSchema(schema).fields;
perms[schema.className] = schema.classLevelPermissions;
});
// Inject the in-memory classes
volatileClasses.forEach(function (className) {
var schema = injectDefaultSchema({ className: className });
data[className] = schema.fields;
perms[className] = schema.classLevelPermissions;
});
_this.data = data;
_this.perms = perms;
delete _this.reloadDataPromise;
}, function (err) {
_this.data = {};
_this.perms = {};
delete _this.reloadDataPromise;
throw err;
});
return this.reloadDataPromise;
}
}, {
key: 'getAllClasses',
value: function getAllClasses() {
var _this2 = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { clearCache: false };
var promise = Promise.resolve();
if (options.clearCache) {
promise = this._cache.clear();
}
return promise.then(function () {
return _this2._cache.getAllClasses();
}).then(function (allClasses) {
if (allClasses && allClasses.length && !options.clearCache) {
return Promise.resolve(allClasses);
}
return _this2._dbAdapter.getAllClasses().then(function (allSchemas) {
return allSchemas.map(injectDefaultSchema);
}).then(function (allSchemas) {
return _this2._cache.setAllClasses(allSchemas).then(function () {
return allSchemas;
});
});
});
}
}, {
key: 'getOneSchema',
value: function getOneSchema(className) {
var _this3 = this;
var allowVolatileClasses = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { clearCache: false };
var promise = Promise.resolve();
if (options.clearCache) {
promise = this._cache.clear();
}
return promise.then(function () {
if (allowVolatileClasses && volatileClasses.indexOf(className) > -1) {
return Promise.resolve({
className: className,
fields: _this3.data[className],
classLevelPermissions: _this3.perms[className]
});
}
return _this3._cache.getOneSchema(className).then(function (cached) {
if (cached && !options.clearCache) {
return Promise.resolve(cached);
}
return _this3._dbAdapter.getClass(className).then(injectDefaultSchema).then(function (result) {
return _this3._cache.setOneSchema(className, result).then(function () {
return result;
});
});
});
});
}
// Create a new class that includes the three default fields.
// ACL is an implicit column that does not get an entry in the
// _SCHEMAS database. Returns a promise that resolves with the
// created schema, in mongo format.
// on success, and rejects with an error on fail. Ensure you
// have authorization (master key, or client class creation
// enabled) before calling this function.
}, {
key: 'addClassIfNotExists',
value: function addClassIfNotExists(className) {
var _this4 = this;
var fields = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var classLevelPermissions = arguments[2];
var validationError = this.validateNewClass(className, fields, classLevelPermissions);
if (validationError) {
return Promise.reject(validationError);
}
return this._dbAdapter.createClass(className, convertSchemaToAdapterSchema({ fields: fields, classLevelPermissions: classLevelPermissions, className: className })).then(convertAdapterSchemaToParseSchema).then(function (res) {
return _this4._cache.clear().then(function () {
return Promise.resolve(res);
});
}).catch(function (error) {
if (error && error.code === Parse.Error.DUPLICATE_VALUE) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class ' + className + ' already exists.');
} else {
throw error;
}
});
}
}, {
key: 'updateClass',
value: function updateClass(className, submittedFields, classLevelPermissions, database) {
var _this5 = this;
return this.getOneSchema(className).then(function (schema) {
var existingFields = schema.fields;
Object.keys(submittedFields).forEach(function (name) {
var field = submittedFields[name];
if (existingFields[name] && field.__op !== 'Delete') {
throw new Parse.Error(255, 'Field ' + name + ' exists, cannot update.');
}
if (!existingFields[name] && field.__op === 'Delete') {
throw new Parse.Error(255, 'Field ' + name + ' does not exist, cannot delete.');
}
});
delete existingFields._rperm;
delete existingFields._wperm;
var newSchema = buildMergedSchemaObject(existingFields, submittedFields);
var validationError = _this5.validateSchemaData(className, newSchema, classLevelPermissions, Object.keys(existingFields));
if (validationError) {
throw new Parse.Error(validationError.code, validationError.error);
}
// Finally we have checked to make sure the request is valid and we can start deleting fields.
// Do all deletions first, then a single save to _SCHEMA collection to handle all additions.
var deletePromises = [];
var insertedFields = [];
Object.keys(submittedFields).forEach(function (fieldName) {
if (submittedFields[fieldName].__op === 'Delete') {
var promise = _this5.deleteField(fieldName, className, database);
deletePromises.push(promise);
} else {
insertedFields.push(fieldName);
}
});
return Promise.all(deletePromises) // Delete Everything
.then(function () {
return _this5.reloadData({ clearCache: true });
}) // Reload our Schema, so we have all the new values
.then(function () {
var promises = insertedFields.map(function (fieldName) {
var type = submittedFields[fieldName];
return _this5.enforceFieldExists(className, fieldName, type);
});
return Promise.all(promises);
}).then(function () {
return _this5.setPermissions(className, classLevelPermissions, newSchema);
})
//TODO: Move this logic into the database adapter
.then(function () {
return {
className: className,
fields: _this5.data[className],
classLevelPermissions: _this5.perms[className]
};
});
}).catch(function (error) {
if (error === undefined) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class ' + className + ' does not exist.');
} else {
throw error;
}
});
}
// Returns a promise that resolves successfully to the new schema
// object or fails with a reason.
}, {
key: 'enforceClassExists',
value: function enforceClassExists(className) {
var _this6 = this;
if (this.data[className]) {
return Promise.resolve(this);
}
// We don't have this class. Update the schema
return this.addClassIfNotExists(className)
// The schema update succeeded. Reload the schema
.then(function () {
return _this6.reloadData({ clearCache: true });
}).catch(function () {
// The schema update failed. This can be okay - it might
// have failed because there's a race condition and a different
// client is making the exact same schema update that we want.
// So just reload the schema.
return _this6.reloadData({ clearCache: true });
}).then(function () {
// Ensure that the schema now validates
if (_this6.data[className]) {
return _this6;
} else {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'Failed to add ' + className);
}
}).catch(function () {
// The schema still doesn't validate. Give up
throw new Parse.Error(Parse.Error.INVALID_JSON, 'schema class name does not revalidate');
});
}
}, {
key: 'validateNewClass',
value: function validateNewClass(className) {
var fields = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var classLevelPermissions = arguments[2];
if (this.data[className]) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class ' + className + ' already exists.');
}
if (!classNameIsValid(className)) {
return {
code: Parse.Error.INVALID_CLASS_NAME,
error: invalidClassNameMessage(className)
};
}
return this.validateSchemaData(className, fields, classLevelPermissions, []);
}
}, {
key: 'validateSchemaData',
value: function validateSchemaData(className, fields, classLevelPermissions, existingFieldNames) {
for (var fieldName in fields) {
if (existingFieldNames.indexOf(fieldName) < 0) {
if (!fieldNameIsValid(fieldName)) {
return {
code: Parse.Error.INVALID_KEY_NAME,
error: 'invalid field name: ' + fieldName
};
}
if (!fieldNameIsValidForClass(fieldName, className)) {
return {
code: 136,
error: 'field ' + fieldName + ' cannot be added'
};
}
var error = fieldTypeIsInvalid(fields[fieldName]);
if (error) return { code: error.code, error: error.message };
}
}
for (var _fieldName in defaultColumns[className]) {
fields[_fieldName] = defaultColumns[className][_fieldName];
}
var geoPoints = Object.keys(fields).filter(function (key) {
return fields[key] && fields[key].type === 'GeoPoint';
});
if (geoPoints.length > 1) {
return {
code: Parse.Error.INCORRECT_TYPE,
error: 'currently, only one GeoPoint field may exist in an object. Adding ' + geoPoints[1] + ' when ' + geoPoints[0] + ' already exists.'
};
}
validateCLP(classLevelPermissions, fields);
}
// Sets the Class-level permissions for a given className, which must exist.
}, {
key: 'setPermissions',
value: function setPermissions(className, perms, newSchema) {
var _this7 = this;
if (typeof perms === 'undefined') {
return Promise.resolve();
}
validateCLP(perms, newSchema);
return this._dbAdapter.setClassLevelPermissions(className, perms).then(function () {
return _this7.reloadData({ clearCache: true });
});
}
// Returns a promise that resolves successfully to the new schema
// object if the provided className-fieldName-type tuple is valid.
// The className must already be validated.
// If 'freeze' is true, refuse to update the schema for this field.
}, {
key: 'enforceFieldExists',
value: function enforceFieldExists(className, fieldName, type) {
var _this8 = this;
if (fieldName.indexOf(".") > 0) {
// subdocument key (x.y) => ok if x is of type 'object'
fieldName = fieldName.split(".")[0];
type = 'Object';
}
if (!fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid field name: ' + fieldName + '.');
}
// If someone tries to create a new field with null/undefined as the value, return;
if (!type) {
return Promise.resolve(this);
}
return this.reloadData().then(function () {
var expectedType = _this8.getExpectedType(className, fieldName);
if (typeof type === 'string') {
type = { type: type };
}
if (expectedType) {
if (!dbTypeMatchesObjectType(expectedType, type)) {
throw new Parse.Error(Parse.Error.INCORRECT_TYPE, 'schema mismatch for ' + className + '.' + fieldName + '; expected ' + typeToString(expectedType) + ' but got ' + typeToString(type));
}
return _this8;
}
return _this8._dbAdapter.addFieldIfNotExists(className, fieldName, type).then(function () {
// The update succeeded. Reload the schema
return _this8.reloadData({ clearCache: true });
}, function () {
//TODO: introspect the error and only reload if the error is one for which is makes sense to reload
// The update failed. This can be okay - it might have been a race
// condition where another client updated the schema in the same
// way that we wanted to. So, just reload the schema
return _this8.reloadData({ clearCache: true });
}).then(function () {
// Ensure that the schema now validates
if (!dbTypeMatchesObjectType(_this8.getExpectedType(className, fieldName), type)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'Could not add field ' + fieldName);
}
// Remove the cached schema
_this8._cache.clear();
return _this8;
});
});
}
// Delete a field, and remove that data from all objects. This is intended
// to remove unused fields, if other writers are writing objects that include
// this field, the field may reappear. Returns a Promise that resolves with
// no object on success, or rejects with { code, error } on failure.
// Passing the database and prefix is necessary in order to drop relation collections
// and remove fields from objects. Ideally the database would belong to
// a database adapter and this function would close over it or access it via member.
}, {
key: 'deleteField',
value: function deleteField(fieldName, className, database) {
var _this9 = this;
if (!classNameIsValid(className)) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, invalidClassNameMessage(className));
}
if (!fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid field name: ' + fieldName);
}
//Don't allow deleting the default fields.
if (!fieldNameIsValidForClass(fieldName, className)) {
throw new Parse.Error(136, 'field ' + fieldName + ' cannot be changed');
}
return this.getOneSchema(className, false, { clearCache: true }).catch(function (error) {
if (error === undefined) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class ' + className + ' does not exist.');
} else {
throw error;
}
}).then(function (schema) {
if (!schema.fields[fieldName]) {
throw new Parse.Error(255, 'Field ' + fieldName + ' does not exist, cannot delete.');
}
if (schema.fields[fieldName].type == 'Relation') {
//For relations, drop the _Join table
return database.adapter.deleteFields(className, schema, [fieldName]).then(function () {
return database.adapter.deleteClass('_Join:' + fieldName + ':' + className);
});
}
return database.adapter.deleteFields(className, schema, [fieldName]);
}).then(function () {
_this9._cache.clear();
});
}
// Validates an object provided in REST format.
// Returns a promise that resolves to the new schema if this object is
// valid.
}, {
key: 'validateObject',
value: function validateObject(className, object, query) {
var geocount = 0;
var promise = this.enforceClassExists(className);
var _loop = function _loop(fieldName) {
if (object[fieldName] === undefined) {
return 'continue';
}
var expected = getType(object[fieldName]);
if (expected === 'GeoPoint') {
geocount++;
}
if (geocount > 1) {
// Make sure all field validation operations run before we return.
// If not - we are continuing to run logic, but already provided response from the server.
return {
v: promise.then(function () {
return Promise.reject(new Parse.Error(Parse.Error.INCORRECT_TYPE, 'there can only be one geopoint field in a class'));
})
};
}
if (!expected) {
return 'continue';
}
if (fieldName === 'ACL') {
// Every object has ACL implicitly.
return 'continue';
}
promise = promise.then(function (schema) {
return schema.enforceFieldExists(className, fieldName, expected);
});
};
for (var fieldName in object) {
var _ret = _loop(fieldName);
switch (_ret) {
case 'continue':
continue;
default:
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
}
}
promise = thenValidateRequiredColumns(promise, className, object, query);
return promise;
}
// Validates that all the properties are set for the object
}, {
key: 'validateRequiredColumns',
value: function validateRequiredColumns(className, object, query) {
var columns = requiredColumns[className];
if (!columns || columns.length == 0) {
return Promise.resolve(this);
}
var missingColumns = columns.filter(function (column) {
if (query && query.objectId) {
if (object[column] && _typeof(object[column]) === "object") {
// Trying to delete a required column
return object[column].__op == 'Delete';
}
// Not trying to do anything there
return false;
}
return !object[column];
});
if (missingColumns.length > 0) {
throw new Parse.Error(Parse.Error.INCORRECT_TYPE, missingColumns[0] + ' is required.');
}
return Promise.resolve(this);
}
// Validates the base CLP for an operation
}, {
key: 'testBaseCLP',
value: function testBaseCLP(className, aclGroup, operation) {
if (!this.perms[className] || !this.perms[className][operation]) {
return true;
}
var classPerms = this.perms[className];
var perms = classPerms[operation];
// Handle the public scenario quickly
if (perms['*']) {
return true;
}
// Check permissions against the aclGroup provided (array of userId/roles)
if (aclGroup.some(function (acl) {
return perms[acl] === true;
})) {
return true;
}
return false;
}
// Validates an operation passes class-level-permissions set in the schema
}, {
key: 'validatePermission',
value: function validatePermission(className, aclGroup, operation) {
if (this.testBaseCLP(className, aclGroup, operation)) {
return Promise.resolve();
}
if (!this.perms[className] || !this.perms[className][operation]) {
return true;
}
var classPerms = this.perms[className];
var perms = classPerms[operation];
// If only for authenticated users
// make sure we have an aclGroup
if (perms['requiresAuthentication']) {
// If aclGroup has * (public)
if (!aclGroup || aclGroup.length == 0) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Permission denied, user needs to be authenticated.');
} else if (aclGroup.indexOf('*') > -1 && aclGroup.length == 1) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Permission denied, user needs to be authenticated.');
}
// no other CLP than requiresAuthentication
// let's resolve that!
if (Object.keys(perms).length == 1) {
return Promise.resolve();
}
}
// No matching CLP, let's check the Pointer permissions
// And handle those later
var permissionField = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
// Reject create when write lockdown
if (permissionField == 'writeUserFields' && operation == 'create') {
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Permission denied for action ' + operation + ' on class ' + className + '.');
}
// Process the readUserFields later
if (Array.isArray(classPerms[permissionField]) && classPerms[permissionField].length > 0) {
return Promise.resolve();
}
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Permission denied for action ' + operation + ' on class ' + className + '.');
}
// Returns the expected type for a className+key combination
// or undefined if the schema is not set
}, {
key: 'getExpectedType',
value: function getExpectedType(className, fieldName) {
if (this.data && this.data[className]) {
var expectedType = this.data[className][fieldName];
return expectedType === 'map' ? 'Object' : expectedType;
}
return undefined;
}
// Checks if a given class is in the schema.
}, {
key: 'hasClass',
value: function hasClass(className) {
var _this10 = this;
return this.reloadData().then(function () {
return !!_this10.data[className];
});
}
}]);
return SchemaController;
}();
// Returns a promise for a new Schema.
exports.default = SchemaController;
var load = function load(dbAdapter, schemaCache, options) {
var schema = new SchemaController(dbAdapter, schemaCache);
return schema.reloadData(options).then(function () {
return schema;
});
};
// Builds a new schema (in schema API response format) out of an
// existing mongo schema + a schemas API put request. This response
// does not include the default fields, as it is intended to be passed
// to mongoSchemaFromFieldsAndClassName. No validation is done here, it
// is done in mongoSchemaFromFieldsAndClassName.
function buildMergedSchemaObject(existingFields, putRequest) {
var newSchema = {};
var sysSchemaField = Object.keys(defaultColumns).indexOf(existingFields._id) === -1 ? [] : Object.keys(defaultColumns[existingFields._id]);
for (var oldField in existingFields) {
if (oldField !== '_id' && oldField !== 'ACL' && oldField !== 'updatedAt' && oldField !== 'createdAt' && oldField !== 'objectId') {
if (sysSchemaField.length > 0 && sysSchemaField.indexOf(oldField) !== -1) {
continue;
}
var fieldIsDeleted = putRequest[oldField] && putRequest[oldField].__op === 'Delete';
if (!fieldIsDeleted) {
newSchema[oldField] = existingFields[oldField];
}
}
}
for (var newField in putRequest) {
if (newField !== 'objectId' && putRequest[newField].__op !== 'Delete') {
if (sysSchemaField.length > 0 && sysSchemaField.indexOf(newField) !== -1) {
continue;
}
newSchema[newField] = putRequest[newField];
}
}
return newSchema;
}
// Given a schema promise, construct another schema promise that
// validates this field once the schema loads.
function thenValidateRequiredColumns(schemaPromise, className, object, query) {
return schemaPromise.then(function (schema) {
return schema.validateRequiredColumns(className, object, query);
});
}
// Gets the type from a REST API formatted object, where 'type' is
// extended past javascript types to include the rest of the Parse
// type system.
// The output should be a valid schema value.
// TODO: ensure that this is compatible with the format used in Open DB
function getType(obj) {
var type = typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
switch (type) {
case 'boolean':
return 'Boolean';
case 'string':
return 'String';
case 'number':
return 'Number';
case 'map':
case 'object':
if (!obj) {
return undefined;
}
return getObjectType(obj);
case 'function':
case 'symbol':
case 'undefined':
default:
throw 'bad obj: ' + obj;
}
}
// This gets the type for non-JSON types like pointers and files, but
// also gets the appropriate type for $ operators.
// Returns null if the type is unknown.
function getObjectType(obj) {
if (obj instanceof Array) {
return 'Array';
}
if (obj.__type) {
switch (obj.__type) {
case 'Pointer':
if (obj.className) {
return {
type: 'Pointer',
targetClass: obj.className
};
}
break;
case 'Relation':
if (obj.className) {
return {
type: 'Relation',
targetClass: obj.className
};
}
break;
case 'File':
if (obj.name) {
return 'File';
}
break;
case 'Date':
if (obj.iso) {
return 'Date';
}
break;
case 'GeoPoint':
if (obj.latitude != null && obj.longitude != null) {
return 'GeoPoint';
}
break;
case 'Bytes':
if (obj.base64) {
return;
}
break;
}
throw new Parse.Error(Parse.Error.INCORRECT_TYPE, "This is not a valid " + obj.__type);
}
if (obj['$ne']) {
return getObjectType(obj['$ne']);
}
if (obj.__op) {
switch (obj.__op) {
case 'Increment':
return 'Number';
case 'Delete':
return null;
case 'Add':
case 'AddUnique':
case 'Remove':
return 'Array';
case 'AddRelation':
case 'RemoveRelation':
return {
type: 'Relation',
targetClass: obj.objects[0].className
};
case 'Batch':
return getObjectType(obj.ops[0]);
default:
throw 'unexpected op: ' + obj.__op;
}
}
return 'Object';
}
exports.load = load;
exports.classNameIsValid = classNameIsValid;
exports.fieldNameIsValid = fieldNameIsValid;
exports.invalidClassNameMessage = invalidClassNameMessage;
exports.buildMergedSchemaObject = buildMergedSchemaObject;
exports.systemClasses = systemClasses;
exports.defaultColumns = defaultColumns;
exports.convertSchemaToAdapterSchema = convertSchemaToAdapterSchema;
exports.VolatileClassesSchemas = VolatileClassesSchemas;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | 1 1 13 1 1 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UserController = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _cryptoUtils = require('../cryptoUtils');
var _triggers = require('../triggers');
var _AdaptableController2 = require('./AdaptableController');
var _AdaptableController3 = _interopRequireDefault(_AdaptableController2);
var _MailAdapter = require('../Adapters/Email/MailAdapter');
var _MailAdapter2 = _interopRequireDefault(_MailAdapter);
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var RestQuery = require('../RestQuery');
var Auth = require('../Auth');
var UserController = exports.UserController = function (_AdaptableController) {
_inherits(UserController, _AdaptableController);
function UserController(adapter, appId) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
_classCallCheck(this, UserController);
return _possibleConstructorReturn(this, (UserController.__proto__ || Object.getPrototypeOf(UserController)).call(this, adapter, appId, options));
}
_createClass(UserController, [{
key: 'validateAdapter',
value: function validateAdapter(adapter) {
// Allow no adapter
if (!adapter && !this.shouldVerifyEmails) {
return;
}
_get(UserController.prototype.__proto__ || Object.getPrototypeOf(UserController.prototype), 'validateAdapter', this).call(this, adapter);
}
}, {
key: 'expectedAdapterType',
value: function expectedAdapterType() {
return _MailAdapter2.default;
}
}, {
key: 'setEmailVerifyToken',
value: function setEmailVerifyToken(user) {
if (this.shouldVerifyEmails) {
user._email_verify_token = (0, _cryptoUtils.randomString)(25);
user.emailVerified = false;
if (this.config.emailVerifyTokenValidityDuration) {
user._email_verify_token_expires_at = _node2.default._encode(this.config.generateEmailVerifyTokenExpiresAt());
}
}
}
}, {
key: 'verifyEmail',
value: function verifyEmail(username, token) {
if (!this.shouldVerifyEmails) {
// Trying to verify email when not enabled
// TODO: Better error here.
throw undefined;
}
var query = { username: username, _email_verify_token: token };
var updateFields = { emailVerified: true, _email_verify_token: { __op: 'Delete' } };
// if the email verify token needs to be validated then
// add additional query params and additional fields that need to be updated
if (this.config.emailVerifyTokenValidityDuration) {
query.emailVerified = false;
query._email_verify_token_expires_at = { $gt: _node2.default._encode(new Date()) };
updateFields._email_verify_token_expires_at = { __op: 'Delete' };
}
return this.config.database.update('_User', query, updateFields).then(function (document) {
if (!document) {
throw undefined;
}
return Promise.resolve(document);
});
}
}, {
key: 'checkResetTokenValidity',
value: function checkResetTokenValidity(username, token) {
var _this2 = this;
return this.config.database.find('_User', {
username: username,
_perishable_token: token
}, { limit: 1 }).then(function (results) {
if (results.length != 1) {
throw undefined;
}
if (_this2.config.passwordPolicy && _this2.config.passwordPolicy.resetTokenValidityDuration) {
var expiresDate = results[0]._perishable_token_expires_at;
if (expiresDate && expiresDate.__type == 'Date') {
expiresDate = new Date(expiresDate.iso);
}
if (expiresDate < new Date()) throw 'The password reset link has expired';
}
return results[0];
});
}
}, {
key: 'getUserIfNeeded',
value: function getUserIfNeeded(user) {
if (user.username && user.email) {
return Promise.resolve(user);
}
var where = {};
if (user.username) {
where.username = user.username;
}
if (user.email) {
where.email = user.email;
}
var query = new RestQuery(this.config, Auth.master(this.config), '_User', where);
return query.execute().then(function (result) {
if (result.results.length != 1) {
throw undefined;
}
return result.results[0];
});
}
}, {
key: 'sendVerificationEmail',
value: function sendVerificationEmail(user) {
var _this3 = this;
if (!this.shouldVerifyEmails) {
return;
}
var token = encodeURIComponent(user._email_verify_token);
// We may need to fetch the user in case of update email
this.getUserIfNeeded(user).then(function (user) {
var username = encodeURIComponent(user.username);
var link = buildEmailLink(_this3.config.verifyEmailURL, username, token, _this3.config);
var options = {
appName: _this3.config.appName,
link: link,
user: (0, _triggers.inflate)('_User', user)
};
if (_this3.adapter.sendVerificationEmail) {
_this3.adapter.sendVerificationEmail(options);
} else {
_this3.adapter.sendMail(_this3.defaultVerificationEmail(options));
}
});
}
}, {
key: 'setPasswordResetToken',
value: function setPasswordResetToken(email) {
var token = { _perishable_token: (0, _cryptoUtils.randomString)(25) };
if (this.config.passwordPolicy && this.config.passwordPolicy.resetTokenValidityDuration) {
token._perishable_token_expires_at = _node2.default._encode(this.config.generatePasswordResetTokenExpiresAt());
}
return this.config.database.update('_User', { $or: [{ email: email }, { username: email, email: { $exists: false } }] }, token, {}, true);
}
}, {
key: 'sendPasswordResetEmail',
value: function sendPasswordResetEmail(email) {
var _this4 = this;
if (!this.adapter) {
throw "Trying to send a reset password but no adapter is set";
// TODO: No adapter?
}
return this.setPasswordResetToken(email).then(function (user) {
var token = encodeURIComponent(user._perishable_token);
var username = encodeURIComponent(user.username);
var link = buildEmailLink(_this4.config.requestResetPasswordURL, username, token, _this4.config);
var options = {
appName: _this4.config.appName,
link: link,
user: (0, _triggers.inflate)('_User', user)
};
if (_this4.adapter.sendPasswordResetEmail) {
_this4.adapter.sendPasswordResetEmail(options);
} else {
_this4.adapter.sendMail(_this4.defaultResetPasswordEmail(options));
}
return Promise.resolve(user);
});
}
}, {
key: 'updatePassword',
value: function updatePassword(username, token, password) {
var _this5 = this;
return this.checkResetTokenValidity(username, token).then(function (user) {
return updateUserPassword(user.objectId, password, _this5.config);
})
// clear reset password token
.then(function () {
return _this5.config.database.update('_User', { username: username }, {
_perishable_token: { __op: 'Delete' },
_perishable_token_expires_at: { __op: 'Delete' }
});
}).catch(function (error) {
if (error.message) {
// in case of Parse.Error, fail with the error message only
return Promise.reject(error.message);
} else {
return Promise.reject(error);
}
});
}
}, {
key: 'defaultVerificationEmail',
value: function defaultVerificationEmail(_ref) {
var link = _ref.link,
user = _ref.user,
appName = _ref.appName;
var text = "Hi,\n\n" + "You are being asked to confirm the e-mail address " + user.get("email") + " with " + appName + "\n\n" + "" + "Click here to confirm it:\n" + link;
var to = user.get("email");
var subject = 'Please verify your e-mail for ' + appName;
return { text: text, to: to, subject: subject };
}
}, {
key: 'defaultResetPasswordEmail',
value: function defaultResetPasswordEmail(_ref2) {
var link = _ref2.link,
user = _ref2.user,
appName = _ref2.appName;
var text = "Hi,\n\n" + "You requested to reset your password for " + appName + ".\n\n" + "" + "Click here to reset it:\n" + link;
var to = user.get("email") || user.get('username');
var subject = 'Password Reset for ' + appName;
return { text: text, to: to, subject: subject };
}
}, {
key: 'shouldVerifyEmails',
get: function get() {
return this.options.verifyUserEmails;
}
}]);
return UserController;
}(_AdaptableController3.default);
// Mark this private
function updateUserPassword(userId, password, config) {
return _rest2.default.update(config, Auth.master(config), '_User', userId, {
password: password
});
}
function buildEmailLink(destination, username, token, config) {
var usernameAndToken = 'token=' + token + '&username=' + username;
if (config.parseFrameURL) {
var destinationWithoutHost = destination.replace(config.publicServerURL, '');
return config.parseFrameURL + '?link=' + encodeURIComponent(destinationWithoutHost) + '&' + usernameAndToken;
} else {
return destination + '?' + usernameAndToken;
}
}
exports.default = UserController;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| Client.js | 30.11% | (28 / 93) | 20% | (8 / 40) | 33.33% | (5 / 15) | 17.11% | (13 / 76) | |
| Id.js | 67.74% | (21 / 31) | 41.67% | (5 / 12) | 50% | (4 / 8) | 46.67% | (7 / 15) | |
| ParseCloudCodePublisher.js | 69.05% | (29 / 42) | 45% | (9 / 20) | 50% | (5 / 10) | 60% | (15 / 25) | |
| ParseLiveQueryServer.js | 15.38% | (74 / 481) | 10.23% | (22 / 215) | 17.39% | (8 / 46) | 13.01% | (57 / 438) | |
| ParsePubSub.js | 66.67% | (16 / 24) | 30% | (3 / 10) | 66.67% | (2 / 3) | 66.67% | (16 / 24) | |
| ParseWebSocketServer.js | 73.08% | (38 / 52) | 54.55% | (12 / 22) | 57.14% | (8 / 14) | 65.71% | (23 / 35) | |
| QueryTools.js | 7.27% | (12 / 165) | 2.34% | (3 / 128) | 0% | (0 / 9) | 7.36% | (12 / 163) | |
| RequestSchema.js | 100% | (8 / 8) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (8 / 8) | |
| SessionTokenCache.js | 62.07% | (36 / 58) | 53.57% | (15 / 28) | 58.33% | (7 / 12) | 51.22% | (21 / 41) | |
| Subscription.js | 52% | (26 / 50) | 36.36% | (8 / 22) | 50% | (5 / 10) | 36.36% | (12 / 33) | |
| equalObjects.js | 12.9% | (4 / 31) | 7.89% | (3 / 38) | 0% | (0 / 3) | 13.79% | (4 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 1 1 7 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Client = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var dafaultFields = ['className', 'objectId', 'updatedAt', 'createdAt', 'ACL'];
var Client = function () {
function Client(id, parseWebSocket) {
_classCallCheck(this, Client);
this.id = id;
this.parseWebSocket = parseWebSocket;
this.roles = [];
this.subscriptionInfos = new Map();
this.pushConnect = this._pushEvent('connected');
this.pushSubscribe = this._pushEvent('subscribed');
this.pushUnsubscribe = this._pushEvent('unsubscribed');
this.pushCreate = this._pushEvent('create');
this.pushEnter = this._pushEvent('enter');
this.pushUpdate = this._pushEvent('update');
this.pushDelete = this._pushEvent('delete');
this.pushLeave = this._pushEvent('leave');
}
_createClass(Client, [{
key: 'addSubscriptionInfo',
value: function addSubscriptionInfo(requestId, subscriptionInfo) {
this.subscriptionInfos.set(requestId, subscriptionInfo);
}
}, {
key: 'getSubscriptionInfo',
value: function getSubscriptionInfo(requestId) {
return this.subscriptionInfos.get(requestId);
}
}, {
key: 'deleteSubscriptionInfo',
value: function deleteSubscriptionInfo(requestId) {
return this.subscriptionInfos.delete(requestId);
}
}, {
key: '_pushEvent',
value: function _pushEvent(type) {
return function (subscriptionId, parseObjectJSON) {
var response = {
'op': type,
'clientId': this.id
};
if (typeof subscriptionId !== 'undefined') {
response['requestId'] = subscriptionId;
}
if (typeof parseObjectJSON !== 'undefined') {
var fields = void 0;
if (this.subscriptionInfos.has(subscriptionId)) {
fields = this.subscriptionInfos.get(subscriptionId).fields;
}
response['object'] = this._toJSONWithFields(parseObjectJSON, fields);
}
Client.pushResponse(this.parseWebSocket, JSON.stringify(response));
};
}
}, {
key: '_toJSONWithFields',
value: function _toJSONWithFields(parseObjectJSON, fields) {
if (!fields) {
return parseObjectJSON;
}
var limitedParseObject = {};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = dafaultFields[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var field = _step.value;
limitedParseObject[field] = parseObjectJSON[field];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = fields[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _field = _step2.value;
if (_field in parseObjectJSON) {
limitedParseObject[_field] = parseObjectJSON[_field];
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return limitedParseObject;
}
}], [{
key: 'pushResponse',
value: function pushResponse(parseWebSocket, message) {
_logger2.default.verbose('Push Response : %j', message);
parseWebSocket.send(message);
}
}, {
key: 'pushError',
value: function pushError(parseWebSocket, code, error) {
var reconnect = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
Client.pushResponse(parseWebSocket, JSON.stringify({
'op': 'error',
'error': error,
'code': code,
'reconnect': reconnect
}));
}
}]);
return Client;
}();
exports.Client = Client;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 2 1 1 1 1 1 1 | 'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Id = function () {
function Id(className, objectId) {
_classCallCheck(this, Id);
this.className = className;
this.objectId = objectId;
}
_createClass(Id, [{
key: 'toString',
value: function toString() {
return this.className + ':' + this.objectId;
}
}], [{
key: 'fromString',
value: function fromString(str) {
var split = str.split(':');
if (split.length !== 2) {
throw new TypeError('Cannot create Id object from this string');
}
return new Id(split[0], split[1]);
}
}]);
return Id;
}();
module.exports = Id;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1 1 3 1 1 1 1 1 2 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParseCloudCodePublisher = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _ParsePubSub = require('./ParsePubSub');
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ParseCloudCodePublisher = function () {
// config object of the publisher, right now it only contains the redisURL,
// but we may extend it later.
function ParseCloudCodePublisher() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, ParseCloudCodePublisher);
this.parsePublisher = _ParsePubSub.ParsePubSub.createPublisher(config);
}
_createClass(ParseCloudCodePublisher, [{
key: 'onCloudCodeAfterSave',
value: function onCloudCodeAfterSave(request) {
this._onCloudCodeMessage(_node2.default.applicationId + 'afterSave', request);
}
}, {
key: 'onCloudCodeAfterDelete',
value: function onCloudCodeAfterDelete(request) {
this._onCloudCodeMessage(_node2.default.applicationId + 'afterDelete', request);
}
// Request is the request object from cloud code functions. request.object is a ParseObject.
}, {
key: '_onCloudCodeMessage',
value: function _onCloudCodeMessage(type, request) {
_logger2.default.verbose('Raw request from cloud code current : %j | original : %j', request.object, request.original);
// We need the full JSON which includes className
var message = {
currentParseObject: request.object._toFullJSON()
};
if (request.original) {
message.originalParseObject = request.original._toFullJSON();
}
this.parsePublisher.publish(type, JSON.stringify(message));
}
}]);
return ParseCloudCodePublisher;
}();
exports.ParseCloudCodePublisher = ParseCloudCodePublisher;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParseLiveQueryServer = undefined;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _tv = require('tv4');
var _tv2 = _interopRequireDefault(_tv);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _Subscription = require('./Subscription');
var _Client = require('./Client');
var _ParseWebSocketServer = require('./ParseWebSocketServer');
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
var _RequestSchema = require('./RequestSchema');
var _RequestSchema2 = _interopRequireDefault(_RequestSchema);
var _QueryTools = require('./QueryTools');
var _ParsePubSub = require('./ParsePubSub');
var _SessionTokenCache = require('./SessionTokenCache');
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ParseLiveQueryServer = function () {
// className -> (queryHash -> subscription)
function ParseLiveQueryServer(server, config) {
var _this = this;
_classCallCheck(this, ParseLiveQueryServer);
this.clientId = 0;
this.clients = new Map();
this.subscriptions = new Map();
config = config || {};
// Store keys, convert obj to map
var keyPairs = config.keyPairs || {};
this.keyPairs = new Map();
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(keyPairs)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var key = _step.value;
this.keyPairs.set(key, keyPairs[key]);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
Iif (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
Iif (_didIteratorError) {
throw _iteratorError;
}
}
}
_logger2.default.verbose('Support key pairs', this.keyPairs);
// Initialize Parse
_node2.default.Object.disableSingleInstance();
var serverURL = config.serverURL || _node2.default.serverURL;
_node2.default.serverURL = serverURL;
var appId = config.appId || _node2.default.applicationId;
var javascriptKey = _node2.default.javaScriptKey;
var masterKey = config.masterKey || _node2.default.masterKey;
_node2.default.initialize(appId, javascriptKey, masterKey);
// Initialize websocket server
this.parseWebSocketServer = new _ParseWebSocketServer.ParseWebSocketServer(server, function (parseWebsocket) {
return _this._onConnect(parseWebsocket);
}, config.websocketTimeout);
// Initialize subscriber
this.subscriber = _ParsePubSub.ParsePubSub.createSubscriber(config);
this.subscriber.subscribe(_node2.default.applicationId + 'afterSave');
this.subscriber.subscribe(_node2.default.applicationId + 'afterDelete');
// Register message handler for subscriber. When publisher get messages, it will publish message
// to the subscribers and the handler will be called.
this.subscriber.on('message', function (channel, messageStr) {
_logger2.default.verbose('Subscribe messsage %j', messageStr);
var message = void 0;
try {
message = JSON.parse(messageStr);
} catch (e) {
_logger2.default.error('unable to parse message', messageStr, e);
return;
}
_this._inflateParseObject(message);
if (channel === _node2.default.applicationId + 'afterSave') {
_this._onAfterSave(message);
} else if (channel === _node2.default.applicationId + 'afterDelete') {
_this._onAfterDelete(message);
} else {
_logger2.default.error('Get message %s from unknown channel %j', message, channel);
}
});
// Initialize sessionToken cache
this.sessionTokenCache = new _SessionTokenCache.SessionTokenCache(config.cacheTimeout);
}
// Message is the JSON object from publisher. Message.currentParseObject is the ParseObject JSON after changes.
// Message.originalParseObject is the original ParseObject JSON.
// The subscriber we use to get object update from publisher
_createClass(ParseLiveQueryServer, [{
key: '_inflateParseObject',
value: function _inflateParseObject(message) {
// Inflate merged object
var currentParseObject = message.currentParseObject;
var className = currentParseObject.className;
var parseObject = new _node2.default.Object(className);
parseObject._finishFetch(currentParseObject);
message.currentParseObject = parseObject;
// Inflate original object
var originalParseObject = message.originalParseObject;
if (originalParseObject) {
className = originalParseObject.className;
parseObject = new _node2.default.Object(className);
parseObject._finishFetch(originalParseObject);
message.originalParseObject = parseObject;
}
}
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
// Message.originalParseObject is the original ParseObject.
}, {
key: '_onAfterDelete',
value: function _onAfterDelete(message) {
var _this2 = this;
_logger2.default.verbose(_node2.default.applicationId + 'afterDelete is triggered');
var deletedParseObject = message.currentParseObject.toJSON();
var className = deletedParseObject.className;
_logger2.default.verbose('ClassName: %j | ObjectId: %s', className, deletedParseObject.id);
_logger2.default.verbose('Current client number : %d', this.clients.size);
var classSubscriptions = this.subscriptions.get(className);
if (typeof classSubscriptions === 'undefined') {
_logger2.default.debug('Can not find subscriptions under this class ' + className);
return;
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = classSubscriptions.values()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var subscription = _step2.value;
var isSubscriptionMatched = this._matchesSubscription(deletedParseObject, subscription);
if (!isSubscriptionMatched) {
continue;
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
var _loop = function _loop() {
var _step3$value = _slicedToArray(_step3.value, 2),
clientId = _step3$value[0],
requestIds = _step3$value[1];
var client = _this2.clients.get(clientId);
if (typeof client === 'undefined') {
return 'continue';
}
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
var _loop2 = function _loop2() {
var requestId = _step4.value;
var acl = message.currentParseObject.getACL();
// Check ACL
_this2._matchesACL(acl, client, requestId).then(function (isMatched) {
if (!isMatched) {
return null;
}
client.pushDelete(requestId, deletedParseObject);
}, function (error) {
_logger2.default.error('Matching ACL error : ', error);
});
};
for (var _iterator4 = requestIds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
_loop2();
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
};
for (var _iterator3 = _lodash2.default.entries(subscription.clientRequestIds)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _ret = _loop();
if (_ret === 'continue') continue;
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
// Message.originalParseObject is the original ParseObject.
}, {
key: '_onAfterSave',
value: function _onAfterSave(message) {
var _this3 = this;
_logger2.default.verbose(_node2.default.applicationId + 'afterSave is triggered');
var originalParseObject = null;
if (message.originalParseObject) {
originalParseObject = message.originalParseObject.toJSON();
}
var currentParseObject = message.currentParseObject.toJSON();
var className = currentParseObject.className;
_logger2.default.verbose('ClassName: %s | ObjectId: %s', className, currentParseObject.id);
_logger2.default.verbose('Current client number : %d', this.clients.size);
var classSubscriptions = this.subscriptions.get(className);
if (typeof classSubscriptions === 'undefined') {
_logger2.default.debug('Can not find subscriptions under this class ' + className);
return;
}
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
var _loop3 = function _loop3() {
var subscription = _step5.value;
var isOriginalSubscriptionMatched = _this3._matchesSubscription(originalParseObject, subscription);
var isCurrentSubscriptionMatched = _this3._matchesSubscription(currentParseObject, subscription);
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
var _loop4 = function _loop4() {
var _step6$value = _slicedToArray(_step6.value, 2),
clientId = _step6$value[0],
requestIds = _step6$value[1];
var client = _this3.clients.get(clientId);
if (typeof client === 'undefined') {
return 'continue';
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
var _loop5 = function _loop5() {
var requestId = _step7.value;
// Set orignal ParseObject ACL checking promise, if the object does not match
// subscription, we do not need to check ACL
var originalACLCheckingPromise = void 0;
if (!isOriginalSubscriptionMatched) {
originalACLCheckingPromise = _node2.default.Promise.as(false);
} else {
var originalACL = void 0;
if (message.originalParseObject) {
originalACL = message.originalParseObject.getACL();
}
originalACLCheckingPromise = _this3._matchesACL(originalACL, client, requestId);
}
// Set current ParseObject ACL checking promise, if the object does not match
// subscription, we do not need to check ACL
var currentACLCheckingPromise = void 0;
if (!isCurrentSubscriptionMatched) {
currentACLCheckingPromise = _node2.default.Promise.as(false);
} else {
var currentACL = message.currentParseObject.getACL();
currentACLCheckingPromise = _this3._matchesACL(currentACL, client, requestId);
}
_node2.default.Promise.when(originalACLCheckingPromise, currentACLCheckingPromise).then(function (isOriginalMatched, isCurrentMatched) {
_logger2.default.verbose('Original %j | Current %j | Match: %s, %s, %s, %s | Query: %s', originalParseObject, currentParseObject, isOriginalSubscriptionMatched, isCurrentSubscriptionMatched, isOriginalMatched, isCurrentMatched, subscription.hash);
// Decide event type
var type = void 0;
if (isOriginalMatched && isCurrentMatched) {
type = 'Update';
} else if (isOriginalMatched && !isCurrentMatched) {
type = 'Leave';
} else if (!isOriginalMatched && isCurrentMatched) {
if (originalParseObject) {
type = 'Enter';
} else {
type = 'Create';
}
} else {
return null;
}
var functionName = 'push' + type;
client[functionName](requestId, currentParseObject);
}, function (error) {
_logger2.default.error('Matching ACL error : ', error);
});
};
for (var _iterator7 = requestIds[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
_loop5();
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
};
for (var _iterator6 = _lodash2.default.entries(subscription.clientRequestIds)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var _ret4 = _loop4();
if (_ret4 === 'continue') continue;
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
};
for (var _iterator5 = classSubscriptions.values()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
_loop3();
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
}
}, {
key: '_onConnect',
value: function _onConnect(parseWebsocket) {
var _this4 = this;
parseWebsocket.on('message', function (request) {
if (typeof request === 'string') {
try {
request = JSON.parse(request);
} catch (e) {
_logger2.default.error('unable to parse request', request, e);
return;
}
}
_logger2.default.verbose('Request: %j', request);
// Check whether this request is a valid request, return error directly if not
if (!_tv2.default.validate(request, _RequestSchema2.default['general']) || !_tv2.default.validate(request, _RequestSchema2.default[request.op])) {
_Client.Client.pushError(parseWebsocket, 1, _tv2.default.error.message);
_logger2.default.error('Connect message error %s', _tv2.default.error.message);
return;
}
switch (request.op) {
case 'connect':
_this4._handleConnect(parseWebsocket, request);
break;
case 'subscribe':
_this4._handleSubscribe(parseWebsocket, request);
break;
case 'update':
_this4._handleUpdateSubscription(parseWebsocket, request);
break;
case 'unsubscribe':
_this4._handleUnsubscribe(parseWebsocket, request);
break;
default:
_Client.Client.pushError(parseWebsocket, 3, 'Get unknown operation');
_logger2.default.error('Get unknown operation', request.op);
}
});
parseWebsocket.on('disconnect', function () {
_logger2.default.info('Client disconnect: %d', parseWebsocket.clientId);
var clientId = parseWebsocket.clientId;
if (!_this4.clients.has(clientId)) {
_logger2.default.error('Can not find client %d on disconnect', clientId);
return;
}
// Delete client
var client = _this4.clients.get(clientId);
_this4.clients.delete(clientId);
// Delete client from subscriptions
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
try {
for (var _iterator8 = _lodash2.default.entries(client.subscriptionInfos)[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _step8$value = _slicedToArray(_step8.value, 2),
_requestId = _step8$value[0],
subscriptionInfo = _step8$value[1];
var _subscription = subscriptionInfo.subscription;
_subscription.deleteClientSubscription(clientId, _requestId);
// If there is no client which is subscribing this subscription, remove it from subscriptions
var classSubscriptions = _this4.subscriptions.get(_subscription.className);
if (!_subscription.hasSubscribingClient()) {
classSubscriptions.delete(_subscription.hash);
}
// If there is no subscriptions under this class, remove it from subscriptions
if (classSubscriptions.size === 0) {
_this4.subscriptions.delete(_subscription.className);
}
}
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
}
}
_logger2.default.verbose('Current clients %d', _this4.clients.size);
_logger2.default.verbose('Current subscriptions %d', _this4.subscriptions.size);
});
}
}, {
key: '_matchesSubscription',
value: function _matchesSubscription(parseObject, subscription) {
// Object is undefined or null, not match
if (!parseObject) {
return false;
}
return (0, _QueryTools.matchesQuery)(parseObject, subscription.query);
}
}, {
key: '_matchesACL',
value: function _matchesACL(acl, client, requestId) {
var _this5 = this;
// If ACL is undefined or null, or ACL has public read access, return true directly
if (!acl || acl.getPublicReadAccess()) {
return _node2.default.Promise.as(true);
}
// Check subscription sessionToken matches ACL first
var subscriptionInfo = client.getSubscriptionInfo(requestId);
if (typeof subscriptionInfo === 'undefined') {
return _node2.default.Promise.as(false);
}
var subscriptionSessionToken = subscriptionInfo.sessionToken;
return this.sessionTokenCache.getUserId(subscriptionSessionToken).then(function (userId) {
return acl.getReadAccess(userId);
}).then(function (isSubscriptionSessionTokenMatched) {
if (isSubscriptionSessionTokenMatched) {
return _node2.default.Promise.as(true);
}
// Check if the user has any roles that match the ACL
return new _node2.default.Promise(function (resolve, reject) {
// Resolve false right away if the acl doesn't have any roles
var acl_has_roles = Object.keys(acl.permissionsById).some(function (key) {
return key.startsWith("role:");
});
if (!acl_has_roles) {
return resolve(false);
}
_this5.sessionTokenCache.getUserId(subscriptionSessionToken).then(function (userId) {
// Pass along a null if there is no user id
if (!userId) {
return _node2.default.Promise.as(null);
}
// Prepare a user object to query for roles
// To eliminate a query for the user, create one locally with the id
var user = new _node2.default.User();
user.id = userId;
return user;
}).then(function (user) {
// Pass along an empty array (of roles) if no user
if (!user) {
return _node2.default.Promise.as([]);
}
// Then get the user's roles
var rolesQuery = new _node2.default.Query(_node2.default.Role);
rolesQuery.equalTo("users", user);
return rolesQuery.find({ useMasterKey: true });
}).then(function (roles) {
// Finally, see if any of the user's roles allow them read access
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
try {
for (var _iterator9 = roles[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var role = _step9.value;
if (acl.getRoleReadAccess(role)) {
return resolve(true);
}
}
} catch (err) {
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
resolve(false);
}).catch(function (error) {
reject(error);
});
});
}).then(function (isRoleMatched) {
if (isRoleMatched) {
return _node2.default.Promise.as(true);
}
// Check client sessionToken matches ACL
var clientSessionToken = client.sessionToken;
return _this5.sessionTokenCache.getUserId(clientSessionToken).then(function (userId) {
return acl.getReadAccess(userId);
});
}).then(function (isMatched) {
return _node2.default.Promise.as(isMatched);
}, function () {
return _node2.default.Promise.as(false);
});
}
}, {
key: '_handleConnect',
value: function _handleConnect(parseWebsocket, request) {
if (!this._validateKeys(request, this.keyPairs)) {
_Client.Client.pushError(parseWebsocket, 4, 'Key in request is not valid');
_logger2.default.error('Key in request is not valid');
return;
}
var client = new _Client.Client(this.clientId, parseWebsocket);
parseWebsocket.clientId = this.clientId;
this.clientId += 1;
this.clients.set(parseWebsocket.clientId, client);
_logger2.default.info('Create new client: %d', parseWebsocket.clientId);
client.pushConnect();
}
}, {
key: '_validateKeys',
value: function _validateKeys(request, validKeyPairs) {
if (!validKeyPairs || validKeyPairs.size == 0) {
return true;
}
var isValid = false;
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
try {
for (var _iterator10 = validKeyPairs[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var _step10$value = _slicedToArray(_step10.value, 2),
key = _step10$value[0],
secret = _step10$value[1];
if (!request[key] || request[key] !== secret) {
continue;
}
isValid = true;
break;
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
return isValid;
}
}, {
key: '_handleSubscribe',
value: function _handleSubscribe(parseWebsocket, request) {
// If we can not find this client, return error to client
if (!parseWebsocket.hasOwnProperty('clientId')) {
_Client.Client.pushError(parseWebsocket, 2, 'Can not find this client, make sure you connect to server before subscribing');
_logger2.default.error('Can not find this client, make sure you connect to server before subscribing');
return;
}
var client = this.clients.get(parseWebsocket.clientId);
// Get subscription from subscriptions, create one if necessary
var subscriptionHash = (0, _QueryTools.queryHash)(request.query);
// Add className to subscriptions if necessary
var className = request.query.className;
if (!this.subscriptions.has(className)) {
this.subscriptions.set(className, new Map());
}
var classSubscriptions = this.subscriptions.get(className);
var subscription = void 0;
if (classSubscriptions.has(subscriptionHash)) {
subscription = classSubscriptions.get(subscriptionHash);
} else {
subscription = new _Subscription.Subscription(className, request.query.where, subscriptionHash);
classSubscriptions.set(subscriptionHash, subscription);
}
// Add subscriptionInfo to client
var subscriptionInfo = {
subscription: subscription
};
// Add selected fields and sessionToken for this subscription if necessary
if (request.query.fields) {
subscriptionInfo.fields = request.query.fields;
}
if (request.sessionToken) {
subscriptionInfo.sessionToken = request.sessionToken;
}
client.addSubscriptionInfo(request.requestId, subscriptionInfo);
// Add clientId to subscription
subscription.addClientSubscription(parseWebsocket.clientId, request.requestId);
client.pushSubscribe(request.requestId);
_logger2.default.verbose('Create client %d new subscription: %d', parseWebsocket.clientId, request.requestId);
_logger2.default.verbose('Current client number: %d', this.clients.size);
}
}, {
key: '_handleUpdateSubscription',
value: function _handleUpdateSubscription(parseWebsocket, request) {
this._handleUnsubscribe(parseWebsocket, request, false);
this._handleSubscribe(parseWebsocket, request);
}
}, {
key: '_handleUnsubscribe',
value: function _handleUnsubscribe(parseWebsocket, request) {
var notifyClient = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
// If we can not find this client, return error to client
if (!parseWebsocket.hasOwnProperty('clientId')) {
_Client.Client.pushError(parseWebsocket, 2, 'Can not find this client, make sure you connect to server before unsubscribing');
_logger2.default.error('Can not find this client, make sure you connect to server before unsubscribing');
return;
}
var requestId = request.requestId;
var client = this.clients.get(parseWebsocket.clientId);
if (typeof client === 'undefined') {
_Client.Client.pushError(parseWebsocket, 2, 'Cannot find client with clientId ' + parseWebsocket.clientId + '. Make sure you connect to live query server before unsubscribing.');
_logger2.default.error('Can not find this client ' + parseWebsocket.clientId);
return;
}
var subscriptionInfo = client.getSubscriptionInfo(requestId);
if (typeof subscriptionInfo === 'undefined') {
_Client.Client.pushError(parseWebsocket, 2, 'Cannot find subscription with clientId ' + parseWebsocket.clientId + ' subscriptionId ' + requestId + '. Make sure you subscribe to live query server before unsubscribing.');
_logger2.default.error('Can not find subscription with clientId ' + parseWebsocket.clientId + ' subscriptionId ' + requestId);
return;
}
// Remove subscription from client
client.deleteSubscriptionInfo(requestId);
// Remove client from subscription
var subscription = subscriptionInfo.subscription;
var className = subscription.className;
subscription.deleteClientSubscription(parseWebsocket.clientId, requestId);
// If there is no client which is subscribing this subscription, remove it from subscriptions
var classSubscriptions = this.subscriptions.get(className);
if (!subscription.hasSubscribingClient()) {
classSubscriptions.delete(subscription.hash);
}
// If there is no subscriptions under this class, remove it from subscriptions
if (classSubscriptions.size === 0) {
this.subscriptions.delete(className);
}
if (!notifyClient) {
return;
}
client.pushUnsubscribe(request.requestId);
_logger2.default.verbose('Delete client: %d | subscription: %d', parseWebsocket.clientId, request.requestId);
}
}]);
return ParseLiveQueryServer;
}();
exports.ParseLiveQueryServer = ParseLiveQueryServer;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParsePubSub = undefined;
var _AdapterLoader = require('../Adapters/AdapterLoader');
var _EventEmitterPubSub = require('../Adapters/PubSub/EventEmitterPubSub');
var _RedisPubSub = require('../Adapters/PubSub/RedisPubSub');
var ParsePubSub = {};
function useRedis(config) {
var redisURL = config.redisURL;
return typeof redisURL !== 'undefined' && redisURL !== '';
}
ParsePubSub.createPublisher = function (config) {
if (useRedis(config)) {
return _RedisPubSub.RedisPubSub.createPublisher(config);
} else {
var adapter = (0, _AdapterLoader.loadAdapter)(config.pubSubAdapter, _EventEmitterPubSub.EventEmitterPubSub, config);
if (typeof adapter.createPublisher !== 'function') {
throw 'pubSubAdapter should have createPublisher()';
}
return adapter.createPublisher(config);
}
};
ParsePubSub.createSubscriber = function (config) {
Iif (useRedis(config)) {
return _RedisPubSub.RedisPubSub.createSubscriber(config);
} else {
var adapter = (0, _AdapterLoader.loadAdapter)(config.pubSubAdapter, _EventEmitterPubSub.EventEmitterPubSub, config);
Iif (typeof adapter.createSubscriber !== 'function') {
throw 'pubSubAdapter should have createSubscriber()';
}
return adapter.createSubscriber(config);
}
};
exports.ParsePubSub = ParsePubSub;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ParseWebSocket = exports.ParseWebSocketServer = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var typeMap = new Map([['disconnect', 'close']]);
var getWS = function getWS() {
try {
return require('uws');
} catch (e) {
return require('ws');
}
};
var ParseWebSocketServer = exports.ParseWebSocketServer = function ParseWebSocketServer(server, onConnect) {
var websocketTimeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10 * 1000;
_classCallCheck(this, ParseWebSocketServer);
var WebSocketServer = getWS().Server;
var wss = new WebSocketServer({ server: server });
wss.on('listening', function () {
_logger2.default.info('Parse LiveQuery Server starts running');
});
wss.on('connection', function (ws) {
onConnect(new ParseWebSocket(ws));
// Send ping to client periodically
var pingIntervalId = setInterval(function () {
if (ws.readyState == ws.OPEN) {
ws.ping();
} else {
clearInterval(pingIntervalId);
}
}, websocketTimeout);
});
this.server = wss;
};
var ParseWebSocket = exports.ParseWebSocket = function () {
function ParseWebSocket(ws) {
_classCallCheck(this, ParseWebSocket);
this.ws = ws;
}
_createClass(ParseWebSocket, [{
key: 'on',
value: function on(type, callback) {
var wsType = typeMap.has(type) ? typeMap.get(type) : type;
this.ws.on(wsType, callback);
}
}, {
key: 'send',
value: function send(message) {
this.ws.send(message);
}
}]);
return ParseWebSocket;
}();
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var equalObjects = require('./equalObjects'); var Id = require('./Id'); var Parse = require('parse/node'); /** * Query Hashes are deterministic hashes for Parse Queries. * Any two queries that have the same set of constraints will produce the same * hash. This lets us reliably group components by the queries they depend upon, * and quickly determine if a query has changed. */ /** * Convert $or queries into an array of where conditions */ function flattenOrQueries(where) { if (!where.hasOwnProperty('$or')) { return where; } var accum = []; for (var i = 0; i < where.$or.length; i++) { accum = accum.concat(where.$or[i]); } return accum; } /** * Deterministically turns an object into a string. Disregards ordering */ function stringify(object) { if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) !== 'object' || object === null) { if (typeof object === 'string') { return '"' + object.replace(/\|/g, '%|') + '"'; } return object + ''; } if (Array.isArray(object)) { var copy = object.map(stringify); copy.sort(); return '[' + copy.join(',') + ']'; } var sections = []; var keys = Object.keys(object); keys.sort(); for (var k = 0; k < keys.length; k++) { sections.push(stringify(keys[k]) + ':' + stringify(object[keys[k]])); } return '{' + sections.join(',') + '}'; } /** * Generate a hash from a query, with unique fields for columns, values, order, * skip, and limit. */ function queryHash(query) { if (query instanceof Parse.Query) { query = { className: query.className, where: query._where }; } var where = flattenOrQueries(query.where || {}); var columns = []; var values = []; var i; if (Array.isArray(where)) { var uniqueColumns = {}; for (i = 0; i < where.length; i++) { var subValues = {}; var keys = Object.keys(where[i]); keys.sort(); for (var j = 0; j < keys.length; j++) { subValues[keys[j]] = where[i][keys[j]]; uniqueColumns[keys[j]] = true; } values.push(subValues); } columns = Object.keys(uniqueColumns); columns.sort(); } else { columns = Object.keys(where); columns.sort(); for (i = 0; i < columns.length; i++) { values.push(where[columns[i]]); } } var sections = [columns.join(','), stringify(values)]; return query.className + ':' + sections.join('|'); } /** * matchesQuery -- Determines if an object would be returned by a Parse Query * It's a lightweight, where-clause only implementation of a full query engine. * Since we find queries that match objects, rather than objects that match * queries, we can avoid building a full-blown query tool. */ function matchesQuery(object, query) { if (query instanceof Parse.Query) { var className = object.id instanceof Id ? object.id.className : object.className; if (className !== query.className) { return false; } return matchesQuery(object, query._where); } for (var field in query) { if (!matchesKeyConstraints(object, field, query[field])) { return false; } } return true; } function equalObjectsGeneric(obj, compareTo, eqlFn) { if (Array.isArray(obj)) { for (var i = 0; i < obj.length; i++) { if (eqlFn(obj[i], compareTo)) { return true; } } return false; } return eqlFn(obj, compareTo); } /** * Determines whether an object matches a single key's constraints */ function matchesKeyConstraints(object, key, constraints) { if (constraints === null) { return false; } if (key.indexOf(".") >= 0) { // Key references a subobject var keyComponents = key.split("."); var subObjectKey = keyComponents[0]; var keyRemainder = keyComponents.slice(1).join("."); return matchesKeyConstraints(object[subObjectKey] || {}, keyRemainder, constraints); } var i; if (key === '$or') { for (i = 0; i < constraints.length; i++) { if (matchesQuery(object, constraints[i])) { return true; } } return false; } if (key === '$relatedTo') { // Bail! We can't handle relational queries locally return false; } // Equality (or Array contains) cases if ((typeof constraints === 'undefined' ? 'undefined' : _typeof(constraints)) !== 'object') { if (Array.isArray(object[key])) { return object[key].indexOf(constraints) > -1; } return object[key] === constraints; } var compareTo; if (constraints.__type) { if (constraints.__type === 'Pointer') { return equalObjectsGeneric(object[key], constraints, function (obj, ptr) { return typeof obj !== 'undefined' && ptr.className === obj.className && ptr.objectId === obj.objectId; }); } return equalObjectsGeneric(object[key], Parse._decode(key, constraints), equalObjects); } // More complex cases for (var condition in constraints) { compareTo = constraints[condition]; if (compareTo.__type) { compareTo = Parse._decode(key, compareTo); } switch (condition) { case '$lt': if (object[key] >= compareTo) { return false; } break; case '$lte': if (object[key] > compareTo) { return false; } break; case '$gt': if (object[key] <= compareTo) { return false; } break; case '$gte': if (object[key] < compareTo) { return false; } break; case '$ne': if (equalObjects(object[key], compareTo)) { return false; } break; case '$in': if (compareTo.indexOf(object[key]) < 0) { return false; } break; case '$nin': if (compareTo.indexOf(object[key]) > -1) { return false; } break; case '$all': for (i = 0; i < compareTo.length; i++) { if (object[key].indexOf(compareTo[i]) < 0) { return false; } } break; case '$exists': { var propertyExists = typeof object[key] !== 'undefined'; var existenceIsRequired = constraints['$exists']; if (typeof constraints['$exists'] !== 'boolean') { // The SDK will never submit a non-boolean for $exists, but if someone // tries to submit a non-boolean for $exits outside the SDKs, just ignore it. break; } if (!propertyExists && existenceIsRequired || propertyExists && !existenceIsRequired) { return false; } break; } case '$regex': if ((typeof compareTo === 'undefined' ? 'undefined' : _typeof(compareTo)) === 'object') { return compareTo.test(object[key]); } // JS doesn't support perl-style escaping var expString = ''; var escapeEnd = -2; var escapeStart = compareTo.indexOf('\\Q'); while (escapeStart > -1) { // Add the unescaped portion expString += compareTo.substring(escapeEnd + 2, escapeStart); escapeEnd = compareTo.indexOf('\\E', escapeStart); if (escapeEnd > -1) { expString += compareTo.substring(escapeStart + 2, escapeEnd).replace(/\\\\\\\\E/g, '\\E').replace(/\W/g, '\\$&'); } escapeStart = compareTo.indexOf('\\Q', escapeEnd); } expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2)); var exp = new RegExp(expString, constraints.$options || ''); if (!exp.test(object[key])) { return false; } break; case '$nearSphere': var distance = compareTo.radiansTo(object[key]); var max = constraints.$maxDistance || Infinity; return distance <= max; case '$within': var southWest = compareTo.$box[0]; var northEast = compareTo.$box[1]; if (southWest.latitude > northEast.latitude || southWest.longitude > northEast.longitude) { // Invalid box, crosses the date line return false; } return object[key].latitude > southWest.latitude && object[key].latitude < northEast.latitude && object[key].longitude > southWest.longitude && object[key].longitude < northEast.longitude; case '$options': // Not a query type, but a way to add options to $regex. Ignore and // avoid the default break; case '$maxDistance': // Not a query type, but a way to add a cap to $nearSphere. Ignore and // avoid the default break; case '$select': return false; case '$dontSelect': return false; default: return false; } } return true; } var QueryTools = { queryHash: queryHash, matchesQuery: matchesQuery }; module.exports = QueryTools; |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var general = {
'title': 'General request schema',
'type': 'object',
'properties': {
'op': {
'type': 'string',
'enum': ['connect', 'subscribe', 'unsubscribe', 'update']
}
}
};
var connect = {
'title': 'Connect operation schema',
'type': 'object',
'properties': {
'op': 'connect',
'applicationId': {
'type': 'string'
},
'javascriptKey': {
type: 'string'
},
'masterKey': {
type: 'string'
},
'clientKey': {
type: 'string'
},
'windowsKey': {
type: 'string'
},
'restAPIKey': {
'type': 'string'
},
'sessionToken': {
'type': 'string'
}
},
'required': ['op', 'applicationId'],
"additionalProperties": false
};
var subscribe = {
'title': 'Subscribe operation schema',
'type': 'object',
'properties': {
'op': 'subscribe',
'requestId': {
'type': 'number'
},
'query': {
'title': 'Query field schema',
'type': 'object',
'properties': {
'className': {
'type': 'string'
},
'where': {
'type': 'object'
},
'fields': {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
'required': ['where', 'className'],
'additionalProperties': false
},
'sessionToken': {
'type': 'string'
}
},
'required': ['op', 'requestId', 'query'],
'additionalProperties': false
};
var update = {
'title': 'Update operation schema',
'type': 'object',
'properties': {
'op': 'update',
'requestId': {
'type': 'number'
},
'query': {
'title': 'Query field schema',
'type': 'object',
'properties': {
'className': {
'type': 'string'
},
'where': {
'type': 'object'
},
'fields': {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
'required': ['where', 'className'],
'additionalProperties': false
},
'sessionToken': {
'type': 'string'
}
},
'required': ['op', 'requestId', 'query'],
'additionalProperties': false
};
var unsubscribe = {
'title': 'Unsubscribe operation schema',
'type': 'object',
'properties': {
'op': 'unsubscribe',
'requestId': {
'type': 'number'
}
},
'required': ['op', 'requestId'],
"additionalProperties": false
};
var RequestSchema = {
'general': general,
'connect': connect,
'subscribe': subscribe,
'update': update,
'unsubscribe': unsubscribe
};
exports.default = RequestSchema;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SessionTokenCache = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _lruCache = require('lru-cache');
var _lruCache2 = _interopRequireDefault(_lruCache);
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function userForSessionToken(sessionToken) {
var q = new _node2.default.Query("_Session");
q.equalTo("sessionToken", sessionToken);
return q.first({ useMasterKey: true }).then(function (session) {
if (!session) {
return _node2.default.Promise.error("No session found for session token");
}
return session.get("user");
});
}
var SessionTokenCache = function () {
function SessionTokenCache() {
var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 30 * 24 * 60 * 60 * 1000;
var maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10000;
_classCallCheck(this, SessionTokenCache);
this.cache = new _lruCache2.default({
max: maxSize,
maxAge: timeout
});
}
_createClass(SessionTokenCache, [{
key: 'getUserId',
value: function getUserId(sessionToken) {
var _this = this;
if (!sessionToken) {
return _node2.default.Promise.error('Empty sessionToken');
}
var userId = this.cache.get(sessionToken);
if (userId) {
_logger2.default.verbose('Fetch userId %s of sessionToken %s from Cache', userId, sessionToken);
return _node2.default.Promise.as(userId);
}
return userForSessionToken(sessionToken).then(function (user) {
_logger2.default.verbose('Fetch userId %s of sessionToken %s from Parse', user.id, sessionToken);
var userId = user.id;
_this.cache.set(sessionToken, userId);
return _node2.default.Promise.as(userId);
}, function (error) {
_logger2.default.error('Can not fetch userId for sessionToken %j, error %j', sessionToken, error);
return _node2.default.Promise.error(error);
});
}
}]);
return SessionTokenCache;
}();
exports.SessionTokenCache = SessionTokenCache;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1 1 3 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Subscription = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Subscription = function () {
// It is query condition eg query.where
function Subscription(className, query, queryHash) {
_classCallCheck(this, Subscription);
this.className = className;
this.query = query;
this.hash = queryHash;
this.clientRequestIds = new Map();
}
_createClass(Subscription, [{
key: 'addClientSubscription',
value: function addClientSubscription(clientId, requestId) {
if (!this.clientRequestIds.has(clientId)) {
this.clientRequestIds.set(clientId, []);
}
var requestIds = this.clientRequestIds.get(clientId);
requestIds.push(requestId);
}
}, {
key: 'deleteClientSubscription',
value: function deleteClientSubscription(clientId, requestId) {
var requestIds = this.clientRequestIds.get(clientId);
if (typeof requestIds === 'undefined') {
_logger2.default.error('Can not find client %d to delete', clientId);
return;
}
var index = requestIds.indexOf(requestId);
if (index < 0) {
_logger2.default.error('Can not find client %d subscription %d to delete', clientId, requestId);
return;
}
requestIds.splice(index, 1);
// Delete client reference if it has no subscription
if (requestIds.length == 0) {
this.clientRequestIds.delete(clientId);
}
}
}, {
key: 'hasSubscribingClient',
value: function hasSubscribingClient() {
return this.clientRequestIds.size > 0;
}
}]);
return Subscription;
}();
exports.Subscription = Subscription;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 | 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var toString = Object.prototype.toString; /** * Determines whether two objects represent the same primitive, special Parse * type, or full Parse Object. */ function equalObjects(a, b) { if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) !== (typeof b === 'undefined' ? 'undefined' : _typeof(b))) { return false; } if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) !== 'object') { return a === b; } if (a === b) { return true; } if (toString.call(a) === '[object Date]') { if (toString.call(b) === '[object Date]') { return +a === +b; } return false; } if (Array.isArray(a)) { if (Array.isArray(b)) { if (a.length !== b.length) { return false; } for (var i = 0; i < a.length; i++) { if (!equalObjects(a[i], b[i])) { return false; } } return true; } return false; } if (Object.keys(a).length !== Object.keys(b).length) { return false; } for (var key in a) { if (!equalObjects(a[key], b[key])) { return false; } } return true; } module.exports = equalObjects; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| PushQueue.js | 56.6% | (30 / 53) | 30.77% | (8 / 26) | 45.45% | (5 / 11) | 41.67% | (15 / 36) | |
| PushWorker.js | 43.96% | (40 / 91) | 26.47% | (9 / 34) | 29.41% | (5 / 17) | 35.14% | (26 / 74) | |
| utils.js | 40.91% | (9 / 22) | 12.5% | (3 / 24) | 33.33% | (1 / 3) | 38.1% | (8 / 21) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PushQueue = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _ParseMessageQueue = require('../ParseMessageQueue');
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _utils = require('./utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PUSH_CHANNEL = 'parse-server-push';
var DEFAULT_BATCH_SIZE = 100;
var PushQueue = exports.PushQueue = function () {
// config object of the publisher, right now it only contains the redisURL,
// but we may extend it later.
function PushQueue() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, PushQueue);
this.channel = config.channel || PUSH_CHANNEL;
this.batchSize = config.batchSize || DEFAULT_BATCH_SIZE;
this.parsePublisher = _ParseMessageQueue.ParseMessageQueue.createPublisher(config);
}
_createClass(PushQueue, [{
key: 'enqueue',
value: function enqueue(body, where, config, auth, pushStatus) {
var _this = this;
var limit = this.batchSize;
// Order by badge (because the payload is badge dependant)
// and createdAt to fix the order
var order = (0, _utils.isPushIncrementing)(body) ? 'badge,createdAt' : 'createdAt';
return Promise.resolve().then(function () {
return _rest2.default.find(config, auth, '_Installation', where, { limit: 0, count: true });
}).then(function (_ref) {
var results = _ref.results,
count = _ref.count;
if (!results) {
return Promise.reject({ error: 'PushController: no results in query' });
}
pushStatus.setRunning(count);
var skip = 0;
while (skip < count) {
var query = { where: where,
limit: limit,
skip: skip,
order: order };
var pushWorkItem = {
body: body,
query: query,
pushStatus: { objectId: pushStatus.objectId },
applicationId: config.applicationId
};
_this.parsePublisher.publish(_this.channel, JSON.stringify(pushWorkItem));
skip += limit;
}
});
}
}], [{
key: 'defaultPushChannel',
value: function defaultPushChannel() {
return PUSH_CHANNEL;
}
}]);
return PushQueue;
}();
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PushWorker = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _deepcopy = require('deepcopy');
var _deepcopy2 = _interopRequireDefault(_deepcopy);
var _AdaptableController = require('../Controllers/AdaptableController');
var _AdaptableController2 = _interopRequireDefault(_AdaptableController);
var _Auth = require('../Auth');
var _Config = require('../Config');
var _Config2 = _interopRequireDefault(_Config);
var _PushAdapter = require('../Adapters/Push/PushAdapter');
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _StatusHandler = require('../StatusHandler');
var _utils = require('./utils');
var _ParseMessageQueue = require('../ParseMessageQueue');
var _PushQueue = require('./PushQueue');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var UNSUPPORTED_BADGE_KEY = "unsupported";
function groupByBadge(installations) {
return installations.reduce(function (map, installation) {
var badge = installation.badge + '';
if (installation.deviceType != "ios") {
badge = UNSUPPORTED_BADGE_KEY;
}
map[badge] = map[badge] || [];
map[badge].push(installation);
return map;
}, {});
}
var PushWorker = exports.PushWorker = function () {
function PushWorker(pushAdapter) {
var _this = this;
var subscriberConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, PushWorker);
_AdaptableController2.default.validateAdapter(pushAdapter, this, _PushAdapter.PushAdapter);
this.adapter = pushAdapter;
this.channel = subscriberConfig.channel || _PushQueue.PushQueue.defaultPushChannel();
this.subscriber = _ParseMessageQueue.ParseMessageQueue.createSubscriber(subscriberConfig);
if (this.subscriber) {
var subscriber = this.subscriber;
subscriber.subscribe(this.channel);
subscriber.on('message', function (channel, messageStr) {
var workItem = JSON.parse(messageStr);
_this.run(workItem);
});
}
}
_createClass(PushWorker, [{
key: 'unsubscribe',
value: function unsubscribe() {
if (this.subscriber) {
this.subscriber.unsubscribe(this.channel);
}
}
}, {
key: 'run',
value: function run(_ref) {
var _this2 = this;
var body = _ref.body,
query = _ref.query,
pushStatus = _ref.pushStatus,
applicationId = _ref.applicationId;
var config = new _Config2.default(applicationId);
var auth = (0, _Auth.master)(config);
var where = query.where;
delete query.where;
return _rest2.default.find(config, auth, '_Installation', where, query).then(function (_ref2) {
var results = _ref2.results;
if (results.length == 0) {
return;
}
return _this2.sendToAdapter(body, results, pushStatus, config);
}, function (err) {
throw err;
});
}
}, {
key: 'sendToAdapter',
value: function sendToAdapter(body, installations, pushStatus, config) {
var _this3 = this;
pushStatus = (0, _StatusHandler.pushStatusHandler)(config, pushStatus.objectId);
if (!(0, _utils.isPushIncrementing)(body)) {
return this.adapter.send(body, installations, pushStatus.objectId).then(function (results) {
return pushStatus.trackSent(results);
});
}
// Collect the badges to reduce the # of calls
var badgeInstallationsMap = groupByBadge(installations);
// Map the on the badges count and return the send result
var promises = Object.keys(badgeInstallationsMap).map(function (badge) {
var payload = (0, _deepcopy2.default)(body);
if (badge == UNSUPPORTED_BADGE_KEY) {
delete payload.data.badge;
} else {
payload.data.badge = parseInt(badge);
}
var installations = badgeInstallationsMap[badge];
return _this3.sendToAdapter(payload, installations, pushStatus, config);
});
return Promise.all(promises);
}
}]);
return PushWorker;
}();
exports.default = PushWorker;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isPushIncrementing = isPushIncrementing;
exports.validatePushType = validatePushType;
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function isPushIncrementing(body) {
return body.data && body.data.badge && typeof body.data.badge == 'string' && body.data.badge.toLowerCase() == "increment";
}
/**
* Check whether the deviceType parameter in qury condition is valid or not.
* @param {Object} where A query condition
* @param {Array} validPushTypes An array of valid push types(string)
*/
function validatePushType() {
var where = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var validPushTypes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var deviceTypeField = where.deviceType || {};
var deviceTypes = [];
if (typeof deviceTypeField === 'string') {
deviceTypes.push(deviceTypeField);
} else if (Array.isArray(deviceTypeField['$in'])) {
deviceTypes.concat(deviceTypeField['$in']);
}
for (var i = 0; i < deviceTypes.length; i++) {
var deviceType = deviceTypes[i];
if (validPushTypes.indexOf(deviceType) < 0) {
throw new _node2.default.Error(_node2.default.Error.PUSH_MISCONFIGURED, deviceType + ' is not supported push type.');
}
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| AnalyticsRouter.js | 69.39% | (34 / 49) | 42.42% | (14 / 33) | 50% | (6 / 12) | 66.67% | (16 / 24) | |
| ClassesRouter.js | 23.16% | (44 / 190) | 13.04% | (15 / 115) | 25.93% | (7 / 27) | 16.31% | (23 / 141) | |
| CloudCodeRouter.js | 72.34% | (34 / 47) | 40% | (14 / 35) | 50% | (6 / 12) | 68.18% | (15 / 22) | |
| FeaturesRouter.js | 66.67% | (38 / 57) | 41.46% | (17 / 41) | 58.33% | (7 / 12) | 78.26% | (18 / 23) | |
| FilesRouter.js | 27.63% | (42 / 152) | 17.65% | (12 / 68) | 23.08% | (6 / 26) | 20.63% | (26 / 126) | |
| FunctionsRouter.js | 35.29% | (42 / 119) | 22.22% | (18 / 81) | 22.22% | (6 / 27) | 25% | (23 / 92) | |
| GlobalConfigRouter.js | 54.29% | (38 / 70) | 39.53% | (17 / 43) | 38.89% | (7 / 18) | 50% | (18 / 36) | |
| HooksRouter.js | 35.78% | (39 / 109) | 23.61% | (17 / 72) | 25% | (7 / 28) | 25.33% | (19 / 75) | |
| IAPValidationRouter.js | 50% | (45 / 90) | 26.87% | (18 / 67) | 24% | (6 / 25) | 42.86% | (27 / 63) | |
| InstallationsRouter.js | 39.13% | (36 / 92) | 23.81% | (15 / 63) | 27.27% | (6 / 22) | 33.96% | (18 / 53) | |
| LogsRouter.js | 55.71% | (39 / 70) | 36.17% | (17 / 47) | 46.67% | (7 / 15) | 52.78% | (19 / 36) | |
| PublicAPIRouter.js | 34.59% | (46 / 133) | 22.06% | (15 / 68) | 17.65% | (6 / 34) | 29.79% | (28 / 94) | |
| PurgeRouter.js | 59.38% | (38 / 64) | 37.78% | (17 / 45) | 50% | (7 / 14) | 60% | (18 / 30) | |
| PushRouter.js | 51.28% | (40 / 78) | 32.08% | (17 / 53) | 46.67% | (7 / 15) | 43.18% | (19 / 44) | |
| RolesRouter.js | 43.59% | (34 / 78) | 26.42% | (14 / 53) | 28.57% | (6 / 21) | 41.03% | (16 / 39) | |
| SchemasRouter.js | 45.36% | (44 / 97) | 27.87% | (17 / 61) | 25.93% | (7 / 27) | 38.1% | (24 / 63) | |
| SessionsRouter.js | 39.81% | (43 / 108) | 23.81% | (15 / 63) | 21.43% | (6 / 28) | 36.23% | (25 / 69) | |
| UsersRouter.js | 24.88% | (51 / 205) | 11.81% | (15 / 127) | 13.95% | (6 / 43) | 19.88% | (33 / 166) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AnalyticsRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // AnalyticsRouter.js
function appOpened(req) {
var analyticsController = req.config.analyticsController;
return analyticsController.appOpened(req);
}
function trackEvent(req) {
var analyticsController = req.config.analyticsController;
return analyticsController.trackEvent(req);
}
var AnalyticsRouter = exports.AnalyticsRouter = function (_PromiseRouter) {
_inherits(AnalyticsRouter, _PromiseRouter);
function AnalyticsRouter() {
_classCallCheck(this, AnalyticsRouter);
return _possibleConstructorReturn(this, (AnalyticsRouter.__proto__ || Object.getPrototypeOf(AnalyticsRouter)).apply(this, arguments));
}
_createClass(AnalyticsRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
this.route('POST', '/events/AppOpened', appOpened);
this.route('POST', '/events/:eventName', trackEvent);
}
}]);
return AnalyticsRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | 1 1 1 7 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ClassesRouter = undefined;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var ALLOWED_GET_QUERY_KEYS = ['keys', 'include'];
var ClassesRouter = exports.ClassesRouter = function (_PromiseRouter) {
_inherits(ClassesRouter, _PromiseRouter);
function ClassesRouter() {
_classCallCheck(this, ClassesRouter);
return _possibleConstructorReturn(this, (ClassesRouter.__proto__ || Object.getPrototypeOf(ClassesRouter)).apply(this, arguments));
}
_createClass(ClassesRouter, [{
key: 'handleFind',
value: function handleFind(req) {
var body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
var options = {};
var allowConstraints = ['skip', 'limit', 'order', 'count', 'keys', 'include', 'redirectClassNameForKey', 'where'];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(body)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var key = _step.value;
if (allowConstraints.indexOf(key) === -1) {
throw new _node2.default.Error(_node2.default.Error.INVALID_QUERY, 'Invalid parameter for query: ' + key);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (body.skip) {
options.skip = Number(body.skip);
}
if (body.limit || body.limit === 0) {
options.limit = Number(body.limit);
} else {
options.limit = Number(100);
}
if (body.order) {
options.order = String(body.order);
}
if (body.count) {
options.count = true;
}
if (typeof body.keys == 'string') {
options.keys = body.keys;
}
if (body.include) {
options.include = String(body.include);
}
if (body.redirectClassNameForKey) {
options.redirectClassNameForKey = String(body.redirectClassNameForKey);
}
if (typeof body.where === 'string') {
body.where = JSON.parse(body.where);
}
return _rest2.default.find(req.config, req.auth, req.params.className, body.where, options, req.info.clientSDK).then(function (response) {
if (response && response.results) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = response.results[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var result = _step2.value;
if (result.sessionToken) {
result.sessionToken = req.info.sessionToken || result.sessionToken;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
return { response: response };
});
}
// Returns a promise for a {response} object.
}, {
key: 'handleGet',
value: function handleGet(req) {
var body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
var options = {};
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = Object.keys(body)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var key = _step3.value;
if (ALLOWED_GET_QUERY_KEYS.indexOf(key) === -1) {
throw new _node2.default.Error(_node2.default.Error.INVALID_QUERY, 'Improper encode of parameter');
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
if (typeof body.keys == 'string') {
options.keys = body.keys;
}
if (body.include) {
options.include = String(body.include);
}
return _rest2.default.get(req.config, req.auth, req.params.className, req.params.objectId, options, req.info.clientSDK).then(function (response) {
if (!response.results || response.results.length == 0) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Object not found.');
}
if (req.params.className === "_User") {
delete response.results[0].sessionToken;
var user = response.results[0];
if (req.auth.user && user.objectId == req.auth.user.id) {
// Force the session token
response.results[0].sessionToken = req.info.sessionToken;
}
}
return { response: response.results[0] };
});
}
}, {
key: 'handleCreate',
value: function handleCreate(req) {
return _rest2.default.create(req.config, req.auth, req.params.className, req.body, req.info.clientSDK);
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
return _rest2.default.update(req.config, req.auth, req.params.className, req.params.objectId, req.body, req.info.clientSDK);
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
return _rest2.default.del(req.config, req.auth, req.params.className, req.params.objectId, req.info.clientSDK).then(function () {
return { response: {} };
});
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/classes/:className', function (req) {
return _this2.handleFind(req);
});
this.route('GET', '/classes/:className/:objectId', function (req) {
return _this2.handleGet(req);
});
this.route('POST', '/classes/:className', function (req) {
return _this2.handleCreate(req);
});
this.route('PUT', '/classes/:className/:objectId', function (req) {
return _this2.handleUpdate(req);
});
this.route('DELETE', '/classes/:className/:objectId', function (req) {
return _this2.handleDelete(req);
});
}
}], [{
key: 'JSONFromQuery',
value: function JSONFromQuery(query) {
var json = {};
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = _lodash2.default.entries(query)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _step4$value = _slicedToArray(_step4.value, 2),
key = _step4$value[0],
value = _step4$value[1];
try {
json[key] = JSON.parse(value);
} catch (e) {
json[key] = value;
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
return json;
}
}]);
return ClassesRouter;
}(_PromiseRouter3.default);
exports.default = ClassesRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CloudCodeRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var triggers = require('../triggers');
var CloudCodeRouter = exports.CloudCodeRouter = function (_PromiseRouter) {
_inherits(CloudCodeRouter, _PromiseRouter);
function CloudCodeRouter() {
_classCallCheck(this, CloudCodeRouter);
return _possibleConstructorReturn(this, (CloudCodeRouter.__proto__ || Object.getPrototypeOf(CloudCodeRouter)).apply(this, arguments));
}
_createClass(CloudCodeRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
this.route('GET', '/cloud_code/jobs', CloudCodeRouter.getJobs);
}
}], [{
key: 'getJobs',
value: function getJobs(req) {
var config = req.config;
var jobs = triggers.getJobs(config.applicationId) || {};
return Promise.resolve({
response: Object.keys(jobs).map(function (jobName) {
return {
jobName: jobName
};
})
});
}
}]);
return CloudCodeRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FeaturesRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _package = require('../../package.json');
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var FeaturesRouter = exports.FeaturesRouter = function (_PromiseRouter) {
_inherits(FeaturesRouter, _PromiseRouter);
function FeaturesRouter() {
_classCallCheck(this, FeaturesRouter);
return _possibleConstructorReturn(this, (FeaturesRouter.__proto__ || Object.getPrototypeOf(FeaturesRouter)).apply(this, arguments));
}
_createClass(FeaturesRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
this.route('GET', '/serverInfo', middleware.promiseEnforceMasterKeyAccess, function (req) {
var features = {
globalConfig: {
create: true,
read: true,
update: true,
delete: true
},
hooks: {
create: true,
read: true,
update: true,
delete: true
},
cloudCode: {
jobs: true
},
logs: {
level: true,
size: true,
order: true,
until: true,
from: true
},
push: {
immediatePush: req.config.hasPushSupport,
scheduledPush: false,
storedPushData: req.config.hasPushSupport,
pushAudiences: false
},
schemas: {
addField: true,
removeField: true,
addClass: true,
removeClass: true,
clearAllDataFromClass: true,
exportClass: false,
editClassLevelPermissions: true,
editPointerPermissions: true
}
};
return { response: {
features: features,
parseServerVersion: _package.version
} };
});
}
}]);
return FeaturesRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 6 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FilesRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
var _bodyParser = require('body-parser');
var _bodyParser2 = _interopRequireDefault(_bodyParser);
var _middlewares = require('../middlewares');
var Middlewares = _interopRequireWildcard(_middlewares);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _Config = require('../Config');
var _Config2 = _interopRequireDefault(_Config);
var _mime = require('mime');
var _mime2 = _interopRequireDefault(_mime);
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var FilesRouter = exports.FilesRouter = function () {
function FilesRouter() {
_classCallCheck(this, FilesRouter);
}
_createClass(FilesRouter, [{
key: 'expressRouter',
value: function expressRouter() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var router = _express2.default.Router();
router.get('/files/:appId/:filename', this.getHandler);
router.post('/files', function (req, res, next) {
next(new _node2.default.Error(_node2.default.Error.INVALID_FILE_NAME, 'Filename not provided.'));
});
router.post('/files/:filename', Middlewares.allowCrossDomain, _bodyParser2.default.raw({ type: function type() {
return true;
}, limit: options.maxUploadSize || '20mb' }), // Allow uploads without Content-Type, or with any Content-Type.
Middlewares.handleParseHeaders, this.createHandler);
router.delete('/files/:filename', Middlewares.allowCrossDomain, Middlewares.handleParseHeaders, Middlewares.enforceMasterKeyAccess, this.deleteHandler);
return router;
}
}, {
key: 'getHandler',
value: function getHandler(req, res) {
var config = new _Config2.default(req.params.appId);
var filesController = config.filesController;
var filename = req.params.filename;
var contentType = _mime2.default.lookup(filename);
if (isFileStreamable(req, filesController)) {
filesController.getFileStream(config, filename).then(function (stream) {
handleFileStream(stream, req, res, contentType);
}).catch(function () {
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
});
} else {
filesController.getFileData(config, filename).then(function (data) {
res.status(200);
res.set('Content-Type', contentType);
res.set('Content-Length', data.length);
res.end(data);
}).catch(function () {
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
});
}
}
}, {
key: 'createHandler',
value: function createHandler(req, res, next) {
if (!req.body || !req.body.length) {
next(new _node2.default.Error(_node2.default.Error.FILE_SAVE_ERROR, 'Invalid file upload.'));
return;
}
if (req.params.filename.length > 128) {
next(new _node2.default.Error(_node2.default.Error.INVALID_FILE_NAME, 'Filename too long.'));
return;
}
if (!req.params.filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
next(new _node2.default.Error(_node2.default.Error.INVALID_FILE_NAME, 'Filename contains invalid characters.'));
return;
}
var filename = req.params.filename;
var contentType = req.get('Content-type');
var config = req.config;
var filesController = config.filesController;
filesController.createFile(config, filename, req.body, contentType).then(function (result) {
res.status(201);
res.set('Location', result.url);
res.json(result);
}).catch(function (e) {
_logger2.default.error(e.message, e);
next(new _node2.default.Error(_node2.default.Error.FILE_SAVE_ERROR, 'Could not store file.'));
});
}
}, {
key: 'deleteHandler',
value: function deleteHandler(req, res, next) {
var filesController = req.config.filesController;
filesController.deleteFile(req.config, req.params.filename).then(function () {
res.status(200);
// TODO: return useful JSON here?
res.end();
}).catch(function () {
next(new _node2.default.Error(_node2.default.Error.FILE_DELETE_ERROR, 'Could not delete file.'));
});
}
}]);
return FilesRouter;
}();
function isFileStreamable(req, filesController) {
if (req.get('Range')) {
if (!(typeof filesController.adapter.getFileStream === 'function')) {
return false;
}
if (typeof filesController.adapter.constructor.name !== 'undefined') {
if (filesController.adapter.constructor.name == 'GridStoreAdapter') {
return true;
}
}
}
return false;
}
// handleFileStream is licenced under Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/).
// Author: LEROIB at weightingformypizza (https://weightingformypizza.wordpress.com/2015/06/24/stream-html5-media-content-like-video-audio-from-mongodb-using-express-and-gridstore/).
function handleFileStream(stream, req, res, contentType) {
var buffer_size = 1024 * 1024; //1024Kb
// Range request, partiall stream the file
var parts = req.get('Range').replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = partialstart ? parseInt(partialstart, 10) : 0;
var end = partialend ? parseInt(partialend, 10) : stream.length - 1;
var chunksize = end - start + 1;
if (chunksize == 1) {
start = 0;
partialend = false;
}
if (!partialend) {
if (stream.length - 1 - start < buffer_size) {
end = stream.length - 1;
} else {
end = start + buffer_size;
}
chunksize = end - start + 1;
}
if (start == 0 && end == 2) {
chunksize = 1;
}
res.writeHead(206, {
'Content-Range': 'bytes ' + start + '-' + end + '/' + stream.length,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': contentType
});
stream.seek(start, function () {
// get gridFile stream
var gridFileStream = stream.stream(true);
var bufferAvail = 0;
var range = end - start + 1;
var totalbyteswanted = end - start + 1;
var totalbyteswritten = 0;
// write to response
gridFileStream.on('data', function (buff) {
bufferAvail += buff.length;
//Ok check if we have enough to cover our range
if (bufferAvail < range) {
//Not enough bytes to satisfy our full range
if (bufferAvail > 0) {
//Write full buffer
res.write(buff);
totalbyteswritten += buff.length;
range -= buff.length;
bufferAvail -= buff.length;
}
} else {
//Enough bytes to satisfy our full range!
if (bufferAvail > 0) {
var buffer = buff.slice(0, range);
res.write(buffer);
totalbyteswritten += buffer.length;
bufferAvail -= range;
}
}
if (totalbyteswritten >= totalbyteswanted) {
//totalbytes = 0;
stream.close();
res.end();
this.destroy();
}
});
});
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | 1 1 4 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FunctionsRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var _StatusHandler = require('../StatusHandler');
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _logger = require('../logger');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
// FunctionsRouter.js
var Parse = require('parse/node').Parse,
triggers = require('../triggers');
function parseObject(obj) {
if (Array.isArray(obj)) {
return obj.map(function (item) {
return parseObject(item);
});
} else if (obj && obj.__type == 'Date') {
return Object.assign(new Date(obj.iso), obj);
} else if (obj && obj.__type == 'File') {
return Parse.File.fromJSON(obj);
} else if (obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object') {
return parseParams(obj);
} else {
return obj;
}
}
function parseParams(params) {
return _lodash2.default.mapValues(params, parseObject);
}
var FunctionsRouter = exports.FunctionsRouter = function (_PromiseRouter) {
_inherits(FunctionsRouter, _PromiseRouter);
function FunctionsRouter() {
_classCallCheck(this, FunctionsRouter);
return _possibleConstructorReturn(this, (FunctionsRouter.__proto__ || Object.getPrototypeOf(FunctionsRouter)).apply(this, arguments));
}
_createClass(FunctionsRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
this.route('POST', '/functions/:functionName', FunctionsRouter.handleCloudFunction);
this.route('POST', '/jobs/:jobName', _middlewares.promiseEnforceMasterKeyAccess, function (req) {
return FunctionsRouter.handleCloudJob(req);
});
this.route('POST', '/jobs', _middlewares.promiseEnforceMasterKeyAccess, function (req) {
return FunctionsRouter.handleCloudJob(req);
});
}
}], [{
key: 'handleCloudJob',
value: function handleCloudJob(req) {
var jobName = req.params.jobName || req.body.jobName;
var applicationId = req.config.applicationId;
var jobHandler = (0, _StatusHandler.jobStatusHandler)(req.config);
var jobFunction = triggers.getJob(jobName, applicationId);
if (!jobFunction) {
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'Invalid job.');
}
var params = Object.assign({}, req.body, req.query);
params = parseParams(params);
var request = {
params: params,
log: req.config.loggerController,
headers: req.headers,
jobName: jobName
};
var status = {
success: jobHandler.setSucceeded.bind(jobHandler),
error: jobHandler.setFailed.bind(jobHandler),
message: jobHandler.setMessage.bind(jobHandler)
};
return jobHandler.setRunning(jobName, params).then(function (jobStatus) {
request.jobId = jobStatus.objectId;
// run the function async
process.nextTick(function () {
jobFunction(request, status);
});
return {
headers: {
'X-Parse-Job-Status-Id': jobStatus.objectId
},
response: {}
};
});
}
}, {
key: 'createResponseObject',
value: function createResponseObject(resolve, reject, message) {
return {
success: function success(result) {
resolve({
response: {
result: Parse._encode(result)
}
});
},
error: function error(code, message) {
if (!message) {
message = code;
code = Parse.Error.SCRIPT_FAILED;
}
reject(new Parse.Error(code, message));
},
message: message
};
}
}, {
key: 'handleCloudFunction',
value: function handleCloudFunction(req) {
var functionName = req.params.functionName;
var applicationId = req.config.applicationId;
var theFunction = triggers.getFunction(functionName, applicationId);
var theValidator = triggers.getValidator(req.params.functionName, applicationId);
if (theFunction) {
var params = Object.assign({}, req.body, req.query);
params = parseParams(params);
var request = {
params: params,
master: req.auth && req.auth.isMaster,
user: req.auth && req.auth.user,
installationId: req.info.installationId,
log: req.config.loggerController,
headers: req.headers,
functionName: functionName
};
if (theValidator && typeof theValidator === "function") {
var result = theValidator(request);
if (!result) {
throw new Parse.Error(Parse.Error.VALIDATION_ERROR, 'Validation failed.');
}
}
return new Promise(function (resolve, reject) {
var userString = req.auth && req.auth.user ? req.auth.user.id : undefined;
var cleanInput = _logger.logger.truncateLogMessage(JSON.stringify(params));
var response = FunctionsRouter.createResponseObject(function (result) {
try {
var cleanResult = _logger.logger.truncateLogMessage(JSON.stringify(result.response.result));
_logger.logger.info('Ran cloud function ' + functionName + ' for user ' + userString + ' ' + ('with:\n Input: ' + cleanInput + '\n Result: ' + cleanResult), {
functionName: functionName,
params: params,
user: userString
});
resolve(result);
} catch (e) {
reject(e);
}
}, function (error) {
try {
_logger.logger.error('Failed running cloud function ' + functionName + ' for ' + ('user ' + userString + ' with:\n Input: ' + cleanInput + '\n Error: ') + JSON.stringify(error), {
functionName: functionName,
error: error,
params: params,
user: userString
});
reject(error);
} catch (e) {
reject(e);
}
});
// Force the keys before the function calls.
Parse.applicationId = req.config.applicationId;
Parse.javascriptKey = req.config.javascriptKey;
Parse.masterKey = req.config.masterKey;
theFunction(request, response);
});
} else {
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'Invalid function: "' + functionName + '"');
}
}
}]);
return FunctionsRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GlobalConfigRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // global_config.js
var GlobalConfigRouter = exports.GlobalConfigRouter = function (_PromiseRouter) {
_inherits(GlobalConfigRouter, _PromiseRouter);
function GlobalConfigRouter() {
_classCallCheck(this, GlobalConfigRouter);
return _possibleConstructorReturn(this, (GlobalConfigRouter.__proto__ || Object.getPrototypeOf(GlobalConfigRouter)).apply(this, arguments));
}
_createClass(GlobalConfigRouter, [{
key: 'getGlobalConfig',
value: function getGlobalConfig(req) {
return req.config.database.find('_GlobalConfig', { objectId: "1" }, { limit: 1 }).then(function (results) {
if (results.length != 1) {
// If there is no config in the database - return empty config.
return { response: { params: {} } };
}
var globalConfig = results[0];
return { response: { params: globalConfig.params } };
});
}
}, {
key: 'updateGlobalConfig',
value: function updateGlobalConfig(req) {
var params = req.body.params;
// Transform in dot notation to make sure it works
var update = Object.keys(params).reduce(function (acc, key) {
acc['params.' + key] = params[key];
return acc;
}, {});
return req.config.database.update('_GlobalConfig', { objectId: "1" }, update, { upsert: true }).then(function () {
return { response: { result: true } };
});
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/config', function (req) {
return _this2.getGlobalConfig(req);
});
this.route('PUT', '/config', middleware.promiseEnforceMasterKeyAccess, function (req) {
return _this2.updateGlobalConfig(req);
});
}
}]);
return GlobalConfigRouter;
}(_PromiseRouter3.default);
exports.default = GlobalConfigRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | 1 1 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.HooksRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _node = require('parse/node');
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var HooksRouter = exports.HooksRouter = function (_PromiseRouter) {
_inherits(HooksRouter, _PromiseRouter);
function HooksRouter() {
_classCallCheck(this, HooksRouter);
return _possibleConstructorReturn(this, (HooksRouter.__proto__ || Object.getPrototypeOf(HooksRouter)).apply(this, arguments));
}
_createClass(HooksRouter, [{
key: 'createHook',
value: function createHook(aHook, config) {
return config.hooksController.createHook(aHook).then(function (hook) {
return { response: hook };
});
}
}, {
key: 'updateHook',
value: function updateHook(aHook, config) {
return config.hooksController.updateHook(aHook).then(function (hook) {
return { response: hook };
});
}
}, {
key: 'handlePost',
value: function handlePost(req) {
return this.createHook(req.body, req.config);
}
}, {
key: 'handleGetFunctions',
value: function handleGetFunctions(req) {
var hooksController = req.config.hooksController;
if (req.params.functionName) {
return hooksController.getFunction(req.params.functionName).then(function (foundFunction) {
if (!foundFunction) {
throw new _node.Parse.Error(143, 'no function named: ' + req.params.functionName + ' is defined');
}
return Promise.resolve({ response: foundFunction });
});
}
return hooksController.getFunctions().then(function (functions) {
return { response: functions || [] };
}, function (err) {
throw err;
});
}
}, {
key: 'handleGetTriggers',
value: function handleGetTriggers(req) {
var hooksController = req.config.hooksController;
if (req.params.className && req.params.triggerName) {
return hooksController.getTrigger(req.params.className, req.params.triggerName).then(function (foundTrigger) {
if (!foundTrigger) {
throw new _node.Parse.Error(143, 'class ' + req.params.className + ' does not exist');
}
return Promise.resolve({ response: foundTrigger });
});
}
return hooksController.getTriggers().then(function (triggers) {
return { response: triggers || [] };
});
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
var hooksController = req.config.hooksController;
if (req.params.functionName) {
return hooksController.deleteFunction(req.params.functionName).then(function () {
return { response: {} };
});
} else if (req.params.className && req.params.triggerName) {
return hooksController.deleteTrigger(req.params.className, req.params.triggerName).then(function () {
return { response: {} };
});
}
return Promise.resolve({ response: {} });
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
var hook;
if (req.params.functionName && req.body.url) {
hook = {};
hook.functionName = req.params.functionName;
hook.url = req.body.url;
} else if (req.params.className && req.params.triggerName && req.body.url) {
hook = {};
hook.className = req.params.className;
hook.triggerName = req.params.triggerName;
hook.url = req.body.url;
} else {
throw new _node.Parse.Error(143, "invalid hook declaration");
}
return this.updateHook(hook, req.config);
}
}, {
key: 'handlePut',
value: function handlePut(req) {
var body = req.body;
if (body.__op == "Delete") {
return this.handleDelete(req);
} else {
return this.handleUpdate(req);
}
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
this.route('GET', '/hooks/functions', middleware.promiseEnforceMasterKeyAccess, this.handleGetFunctions.bind(this));
this.route('GET', '/hooks/triggers', middleware.promiseEnforceMasterKeyAccess, this.handleGetTriggers.bind(this));
this.route('GET', '/hooks/functions/:functionName', middleware.promiseEnforceMasterKeyAccess, this.handleGetFunctions.bind(this));
this.route('GET', '/hooks/triggers/:className/:triggerName', middleware.promiseEnforceMasterKeyAccess, this.handleGetTriggers.bind(this));
this.route('POST', '/hooks/functions', middleware.promiseEnforceMasterKeyAccess, this.handlePost.bind(this));
this.route('POST', '/hooks/triggers', middleware.promiseEnforceMasterKeyAccess, this.handlePost.bind(this));
this.route('PUT', '/hooks/functions/:functionName', middleware.promiseEnforceMasterKeyAccess, this.handlePut.bind(this));
this.route('PUT', '/hooks/triggers/:className/:triggerName', middleware.promiseEnforceMasterKeyAccess, this.handlePut.bind(this));
}
}]);
return HooksRouter;
}(_PromiseRouter3.default);
exports.default = HooksRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | 1 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.IAPValidationRouter = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require("../PromiseRouter");
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _node = require("parse/node");
var _node2 = _interopRequireDefault(_node);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var request = require("request");
var rest = require("../rest");
// TODO move validation logic in IAPValidationController
var IAP_SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt";
var IAP_PRODUCTION_URL = "https://buy.itunes.apple.com/verifyReceipt";
var APP_STORE_ERRORS = {
21000: "The App Store could not read the JSON object you provided.",
21002: "The data in the receipt-data property was malformed or missing.",
21003: "The receipt could not be authenticated.",
21004: "The shared secret you provided does not match the shared secret on file for your account.",
21005: "The receipt server is not currently available.",
21006: "This receipt is valid but the subscription has expired.",
21007: "This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.",
21008: "This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead."
};
function appStoreError(status) {
status = parseInt(status);
var errorString = APP_STORE_ERRORS[status] || "unknown error.";
return { status: status, error: errorString };
}
function validateWithAppStore(url, receipt) {
return new Promise(function (fulfill, reject) {
request.post({
url: url,
body: { "receipt-data": receipt },
json: true
}, function (err, res, body) {
var status = body.status;
if (status == 0) {
// No need to pass anything, status is OK
return fulfill();
}
// receipt is from test and should go to test
return reject(body);
});
});
}
function getFileForProductIdentifier(productIdentifier, req) {
return rest.find(req.config, req.auth, '_Product', { productIdentifier: productIdentifier }, undefined, req.info.clientSDK).then(function (result) {
var products = result.results;
if (!products || products.length != 1) {
// Error not found or too many
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Object not found.');
}
var download = products[0].download;
return Promise.resolve({ response: download });
});
}
var IAPValidationRouter = exports.IAPValidationRouter = function (_PromiseRouter) {
_inherits(IAPValidationRouter, _PromiseRouter);
function IAPValidationRouter() {
_classCallCheck(this, IAPValidationRouter);
return _possibleConstructorReturn(this, (IAPValidationRouter.__proto__ || Object.getPrototypeOf(IAPValidationRouter)).apply(this, arguments));
}
_createClass(IAPValidationRouter, [{
key: "handleRequest",
value: function handleRequest(req) {
var receipt = req.body.receipt;
var productIdentifier = req.body.productIdentifier;
if (!receipt || !productIdentifier) {
// TODO: Error, malformed request
throw new _node2.default.Error(_node2.default.Error.INVALID_JSON, "missing receipt or productIdentifier");
}
// Transform the object if there
// otherwise assume it's in Base64 already
if ((typeof receipt === "undefined" ? "undefined" : _typeof(receipt)) == "object") {
if (receipt["__type"] == "Bytes") {
receipt = receipt.base64;
}
}
if (process.env.NODE_ENV == "test" && req.body.bypassAppStoreValidation) {
return getFileForProductIdentifier(productIdentifier, req);
}
function successCallback() {
return getFileForProductIdentifier(productIdentifier, req);
}
function errorCallback(error) {
return Promise.resolve({ response: appStoreError(error.status) });
}
return validateWithAppStore(IAP_PRODUCTION_URL, receipt).then(function () {
return successCallback();
}, function (error) {
if (error.status == 21007) {
return validateWithAppStore(IAP_SANDBOX_URL, receipt).then(function () {
return successCallback();
}, function (error) {
return errorCallback(error);
});
}
return errorCallback(error);
});
}
}, {
key: "mountRoutes",
value: function mountRoutes() {
this.route("POST", "/validate_purchase", this.handleRequest);
}
}]);
return IAPValidationRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1 1 6 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.InstallationsRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _ClassesRouter2 = require('./ClassesRouter');
var _ClassesRouter3 = _interopRequireDefault(_ClassesRouter2);
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // InstallationsRouter.js
var InstallationsRouter = exports.InstallationsRouter = function (_ClassesRouter) {
_inherits(InstallationsRouter, _ClassesRouter);
function InstallationsRouter() {
_classCallCheck(this, InstallationsRouter);
return _possibleConstructorReturn(this, (InstallationsRouter.__proto__ || Object.getPrototypeOf(InstallationsRouter)).apply(this, arguments));
}
_createClass(InstallationsRouter, [{
key: 'handleFind',
value: function handleFind(req) {
var body = Object.assign(req.body, _ClassesRouter3.default.JSONFromQuery(req.query));
var options = {};
if (body.skip) {
options.skip = Number(body.skip);
}
if (body.limit || body.limit === 0) {
options.limit = Number(body.limit);
}
if (body.order) {
options.order = String(body.order);
}
if (body.count) {
options.count = true;
}
if (body.include) {
options.include = String(body.include);
}
return _rest2.default.find(req.config, req.auth, '_Installation', body.where, options, req.info.clientSDK).then(function (response) {
return { response: response };
});
}
}, {
key: 'handleGet',
value: function handleGet(req) {
req.params.className = '_Installation';
return _get(InstallationsRouter.prototype.__proto__ || Object.getPrototypeOf(InstallationsRouter.prototype), 'handleGet', this).call(this, req);
}
}, {
key: 'handleCreate',
value: function handleCreate(req) {
req.params.className = '_Installation';
return _get(InstallationsRouter.prototype.__proto__ || Object.getPrototypeOf(InstallationsRouter.prototype), 'handleCreate', this).call(this, req);
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
req.params.className = '_Installation';
return _get(InstallationsRouter.prototype.__proto__ || Object.getPrototypeOf(InstallationsRouter.prototype), 'handleUpdate', this).call(this, req);
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
req.params.className = '_Installation';
return _get(InstallationsRouter.prototype.__proto__ || Object.getPrototypeOf(InstallationsRouter.prototype), 'handleDelete', this).call(this, req);
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/installations', function (req) {
return _this2.handleFind(req);
});
this.route('GET', '/installations/:objectId', function (req) {
return _this2.handleGet(req);
});
this.route('POST', '/installations', function (req) {
return _this2.handleCreate(req);
});
this.route('PUT', '/installations/:objectId', function (req) {
return _this2.handleUpdate(req);
});
this.route('DELETE', '/installations/:objectId', function (req) {
return _this2.handleDelete(req);
});
}
}]);
return InstallationsRouter;
}(_ClassesRouter3.default);
exports.default = InstallationsRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LogsRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _node = require('parse/node');
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var LogsRouter = exports.LogsRouter = function (_PromiseRouter) {
_inherits(LogsRouter, _PromiseRouter);
function LogsRouter() {
_classCallCheck(this, LogsRouter);
return _possibleConstructorReturn(this, (LogsRouter.__proto__ || Object.getPrototypeOf(LogsRouter)).apply(this, arguments));
}
_createClass(LogsRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/scriptlog', middleware.promiseEnforceMasterKeyAccess, this.validateRequest, function (req) {
return _this2.handleGET(req);
});
}
}, {
key: 'validateRequest',
value: function validateRequest(req) {
if (!req.config || !req.config.loggerController) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Logger adapter is not available');
}
}
// Returns a promise for a {response} object.
// query params:
// level (optional) Level of logging you want to query for (info || error)
// from (optional) Start time for the search. Defaults to 1 week ago.
// until (optional) End time for the search. Defaults to current time.
// order (optional) Direction of results returned, either “asc” or “desc”. Defaults to “desc”.
// size (optional) Number of rows returned by search. Defaults to 10
// n same as size, overrides size if set
}, {
key: 'handleGET',
value: function handleGET(req) {
var from = req.query.from;
var until = req.query.until;
var size = req.query.size;
if (req.query.n) {
size = req.query.n;
}
var order = req.query.order;
var level = req.query.level;
var options = {
from: from,
until: until,
size: size,
order: order,
level: level
};
return req.config.loggerController.getLogs(options).then(function (result) {
return Promise.resolve({
response: result
});
});
}
}]);
return LogsRouter;
}(_PromiseRouter3.default);
exports.default = LogsRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | 1 1 9 1 1 1 1 1 1 1 1 1 1 1 1 1 6 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PublicAPIRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _Config = require('../Config');
var _Config2 = _interopRequireDefault(_Config);
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _querystring = require('querystring');
var _querystring2 = _interopRequireDefault(_querystring);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var public_html = _path2.default.resolve(__dirname, "../../public_html");
var views = _path2.default.resolve(__dirname, '../../views');
var PublicAPIRouter = exports.PublicAPIRouter = function (_PromiseRouter) {
_inherits(PublicAPIRouter, _PromiseRouter);
function PublicAPIRouter() {
_classCallCheck(this, PublicAPIRouter);
return _possibleConstructorReturn(this, (PublicAPIRouter.__proto__ || Object.getPrototypeOf(PublicAPIRouter)).apply(this, arguments));
}
_createClass(PublicAPIRouter, [{
key: 'verifyEmail',
value: function verifyEmail(req) {
var _this2 = this;
var _req$query = req.query,
token = _req$query.token,
username = _req$query.username;
var appId = req.params.appId;
var config = new _Config2.default(appId);
if (!config.publicServerURL) {
return this.missingPublicServerURL();
}
if (!token || !username) {
return this.invalidLink(req);
}
var userController = config.userController;
return userController.verifyEmail(username, token).then(function () {
var params = _querystring2.default.stringify({ username: username });
return Promise.resolve({
status: 302,
location: config.verifyEmailSuccessURL + '?' + params
});
}, function () {
return _this2.invalidLink(req);
});
}
}, {
key: 'changePassword',
value: function changePassword(req) {
return new Promise(function (resolve, reject) {
var config = new _Config2.default(req.query.id);
if (!config.publicServerURL) {
return resolve({
status: 404,
text: 'Not found.'
});
}
// Should we keep the file in memory or leave like that?
_fs2.default.readFile(_path2.default.resolve(views, "choose_password"), 'utf-8', function (err, data) {
if (err) {
return reject(err);
}
data = data.replace("PARSE_SERVER_URL", '\'' + config.publicServerURL + '\'');
resolve({
text: data
});
});
});
}
}, {
key: 'requestResetPassword',
value: function requestResetPassword(req) {
var _this3 = this;
var config = req.config;
if (!config.publicServerURL) {
return this.missingPublicServerURL();
}
var _req$query2 = req.query,
username = _req$query2.username,
token = _req$query2.token;
if (!username || !token) {
return this.invalidLink(req);
}
return config.userController.checkResetTokenValidity(username, token).then(function () {
var params = _querystring2.default.stringify({ token: token, id: config.applicationId, username: username, app: config.appName });
return Promise.resolve({
status: 302,
location: config.choosePasswordURL + '?' + params
});
}, function () {
return _this3.invalidLink(req);
});
}
}, {
key: 'resetPassword',
value: function resetPassword(req) {
var config = req.config;
if (!config.publicServerURL) {
return this.missingPublicServerURL();
}
var _req$body = req.body,
username = _req$body.username,
token = _req$body.token,
new_password = _req$body.new_password;
if (!username || !token || !new_password) {
return this.invalidLink(req);
}
return config.userController.updatePassword(username, token, new_password).then(function () {
var params = _querystring2.default.stringify({ username: username });
return Promise.resolve({
status: 302,
location: config.passwordResetSuccessURL + '?' + params
});
}, function (err) {
var params = _querystring2.default.stringify({ username: username, token: token, id: config.applicationId, error: err, app: config.appName });
return Promise.resolve({
status: 302,
location: config.choosePasswordURL + '?' + params
});
});
}
}, {
key: 'invalidLink',
value: function invalidLink(req) {
return Promise.resolve({
status: 302,
location: req.config.invalidLinkURL
});
}
}, {
key: 'missingPublicServerURL',
value: function missingPublicServerURL() {
return Promise.resolve({
text: 'Not found.',
status: 404
});
}
}, {
key: 'setConfig',
value: function setConfig(req) {
req.config = new _Config2.default(req.params.appId);
return Promise.resolve();
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this4 = this;
this.route('GET', '/apps/:appId/verify_email', function (req) {
_this4.setConfig(req);
}, function (req) {
return _this4.verifyEmail(req);
});
this.route('GET', '/apps/choose_password', function (req) {
return _this4.changePassword(req);
});
this.route('POST', '/apps/:appId/request_password_reset', function (req) {
_this4.setConfig(req);
}, function (req) {
return _this4.resetPassword(req);
});
this.route('GET', '/apps/:appId/request_password_reset', function (req) {
_this4.setConfig(req);
}, function (req) {
return _this4.requestResetPassword(req);
});
}
}, {
key: 'expressRouter',
value: function expressRouter() {
var router = _express2.default.Router();
router.use("/apps", _express2.default.static(public_html));
router.use("/", _get(PublicAPIRouter.prototype.__proto__ || Object.getPrototypeOf(PublicAPIRouter.prototype), 'expressRouter', this).call(this));
return router;
}
}]);
return PublicAPIRouter;
}(_PromiseRouter3.default);
exports.default = PublicAPIRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PurgeRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var PurgeRouter = exports.PurgeRouter = function (_PromiseRouter) {
_inherits(PurgeRouter, _PromiseRouter);
function PurgeRouter() {
_classCallCheck(this, PurgeRouter);
return _possibleConstructorReturn(this, (PurgeRouter.__proto__ || Object.getPrototypeOf(PurgeRouter)).apply(this, arguments));
}
_createClass(PurgeRouter, [{
key: 'handlePurge',
value: function handlePurge(req) {
return req.config.database.purgeCollection(req.params.className).then(function () {
var cacheAdapter = req.config.cacheController;
if (req.params.className == '_Session') {
cacheAdapter.user.clear();
} else if (req.params.className == '_Role') {
cacheAdapter.role.clear();
}
return { response: {} };
});
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('DELETE', '/purge/:className', middleware.promiseEnforceMasterKeyAccess, function (req) {
return _this2.handlePurge(req);
});
}
}]);
return PurgeRouter;
}(_PromiseRouter3.default);
exports.default = PurgeRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PushRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Eif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require("../PromiseRouter");
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require("../middlewares");
var middleware = _interopRequireWildcard(_middlewares);
var _node = require("parse/node");
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var PushRouter = exports.PushRouter = function (_PromiseRouter) {
_inherits(PushRouter, _PromiseRouter);
function PushRouter() {
_classCallCheck(this, PushRouter);
return _possibleConstructorReturn(this, (PushRouter.__proto__ || Object.getPrototypeOf(PushRouter)).apply(this, arguments));
}
_createClass(PushRouter, [{
key: "mountRoutes",
value: function mountRoutes() {
this.route("POST", "/push", middleware.promiseEnforceMasterKeyAccess, PushRouter.handlePOST);
}
}], [{
key: "handlePOST",
value: function handlePOST(req) {
var pushController = req.config.pushController;
if (!pushController) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Push controller is not set');
}
var where = PushRouter.getQueryCondition(req);
var resolve = void 0;
var promise = new Promise(function (_resolve) {
resolve = _resolve;
});
pushController.sendPush(req.body, where, req.config, req.auth, function (pushStatusId) {
resolve({
headers: {
'X-Parse-Push-Status-Id': pushStatusId
},
response: {
result: true
}
});
});
return promise;
}
/**
* Get query condition from the request body.
* @param {Object} req A request object
* @returns {Object} The query condition, the where field in a query api call
*/
}, {
key: "getQueryCondition",
value: function getQueryCondition(req) {
var body = req.body || {};
var hasWhere = typeof body.where !== 'undefined';
var hasChannels = typeof body.channels !== 'undefined';
var where = void 0;
if (hasWhere && hasChannels) {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Channels and query can not be set at the same time.');
} else if (hasWhere) {
where = body.where;
} else if (hasChannels) {
where = {
"channels": {
"$in": body.channels
}
};
} else {
throw new _node.Parse.Error(_node.Parse.Error.PUSH_MISCONFIGURED, 'Sending a push requires either "channels" or a "where" query.');
}
return where;
}
}]);
return PushRouter;
}(_PromiseRouter3.default);
exports.default = PushRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1 1 6 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RolesRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _ClassesRouter2 = require('./ClassesRouter');
var _ClassesRouter3 = _interopRequireDefault(_ClassesRouter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var RolesRouter = exports.RolesRouter = function (_ClassesRouter) {
_inherits(RolesRouter, _ClassesRouter);
function RolesRouter() {
_classCallCheck(this, RolesRouter);
return _possibleConstructorReturn(this, (RolesRouter.__proto__ || Object.getPrototypeOf(RolesRouter)).apply(this, arguments));
}
_createClass(RolesRouter, [{
key: 'handleFind',
value: function handleFind(req) {
req.params.className = '_Role';
return _get(RolesRouter.prototype.__proto__ || Object.getPrototypeOf(RolesRouter.prototype), 'handleFind', this).call(this, req);
}
}, {
key: 'handleGet',
value: function handleGet(req) {
req.params.className = '_Role';
return _get(RolesRouter.prototype.__proto__ || Object.getPrototypeOf(RolesRouter.prototype), 'handleGet', this).call(this, req);
}
}, {
key: 'handleCreate',
value: function handleCreate(req) {
req.params.className = '_Role';
return _get(RolesRouter.prototype.__proto__ || Object.getPrototypeOf(RolesRouter.prototype), 'handleCreate', this).call(this, req);
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
req.params.className = '_Role';
return _get(RolesRouter.prototype.__proto__ || Object.getPrototypeOf(RolesRouter.prototype), 'handleUpdate', this).call(this, req);
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
req.params.className = '_Role';
return _get(RolesRouter.prototype.__proto__ || Object.getPrototypeOf(RolesRouter.prototype), 'handleDelete', this).call(this, req);
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/roles', function (req) {
return _this2.handleFind(req);
});
this.route('GET', '/roles/:objectId', function (req) {
return _this2.handleGet(req);
});
this.route('POST', '/roles', function (req) {
return _this2.handleCreate(req);
});
this.route('PUT', '/roles/:objectId', function (req) {
return _this2.handleUpdate(req);
});
this.route('DELETE', '/roles/:objectId', function (req) {
return _this2.handleDelete(req);
});
}
}]);
return RolesRouter;
}(_ClassesRouter3.default);
exports.default = RolesRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SchemasRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _PromiseRouter2 = require('../PromiseRouter');
var _PromiseRouter3 = _interopRequireDefault(_PromiseRouter2);
var _middlewares = require('../middlewares');
var middleware = _interopRequireWildcard(_middlewares);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
// schemas.js
var Parse = require('parse/node').Parse,
SchemaController = require('../Controllers/SchemaController');
function classNameMismatchResponse(bodyClass, pathClass) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class name mismatch between ' + bodyClass + ' and ' + pathClass + '.');
}
function getAllSchemas(req) {
return req.config.database.loadSchema({ clearCache: true }).then(function (schemaController) {
return schemaController.getAllClasses(true);
}).then(function (schemas) {
return { response: { results: schemas } };
});
}
function getOneSchema(req) {
var className = req.params.className;
return req.config.database.loadSchema({ clearCache: true }).then(function (schemaController) {
return schemaController.getOneSchema(className, true);
}).then(function (schema) {
return { response: schema };
}).catch(function (error) {
if (error === undefined) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, 'Class ' + className + ' does not exist.');
} else {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Database adapter error.');
}
});
}
function createSchema(req) {
if (req.params.className && req.body.className) {
if (req.params.className != req.body.className) {
return classNameMismatchResponse(req.body.className, req.params.className);
}
}
var className = req.params.className || req.body.className;
if (!className) {
throw new Parse.Error(135, 'POST ' + req.path + ' needs a class name.');
}
return req.config.database.loadSchema({ clearCache: true }).then(function (schema) {
return schema.addClassIfNotExists(className, req.body.fields, req.body.classLevelPermissions);
}).then(function (schema) {
return { response: schema };
});
}
function modifySchema(req) {
if (req.body.className && req.body.className != req.params.className) {
return classNameMismatchResponse(req.body.className, req.params.className);
}
var submittedFields = req.body.fields || {};
var className = req.params.className;
return req.config.database.loadSchema({ clearCache: true }).then(function (schema) {
return schema.updateClass(className, submittedFields, req.body.classLevelPermissions, req.config.database);
}).then(function (result) {
return { response: result };
});
}
var deleteSchema = function deleteSchema(req) {
if (!SchemaController.classNameIsValid(req.params.className)) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, SchemaController.invalidClassNameMessage(req.params.className));
}
return req.config.database.deleteSchema(req.params.className).then(function () {
return { response: {} };
});
};
var SchemasRouter = exports.SchemasRouter = function (_PromiseRouter) {
_inherits(SchemasRouter, _PromiseRouter);
function SchemasRouter() {
_classCallCheck(this, SchemasRouter);
return _possibleConstructorReturn(this, (SchemasRouter.__proto__ || Object.getPrototypeOf(SchemasRouter)).apply(this, arguments));
}
_createClass(SchemasRouter, [{
key: 'mountRoutes',
value: function mountRoutes() {
this.route('GET', '/schemas', middleware.promiseEnforceMasterKeyAccess, getAllSchemas);
this.route('GET', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, getOneSchema);
this.route('POST', '/schemas', middleware.promiseEnforceMasterKeyAccess, createSchema);
this.route('POST', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, createSchema);
this.route('PUT', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, modifySchema);
this.route('DELETE', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, deleteSchema);
}
}]);
return SchemasRouter;
}(_PromiseRouter3.default);
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SessionsRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _ClassesRouter2 = require('./ClassesRouter');
var _ClassesRouter3 = _interopRequireDefault(_ClassesRouter2);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _Auth = require('../Auth');
var _Auth2 = _interopRequireDefault(_Auth);
var _RestWrite = require('../RestWrite');
var _RestWrite2 = _interopRequireDefault(_RestWrite);
var _cryptoUtils = require('../cryptoUtils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var SessionsRouter = exports.SessionsRouter = function (_ClassesRouter) {
_inherits(SessionsRouter, _ClassesRouter);
function SessionsRouter() {
_classCallCheck(this, SessionsRouter);
return _possibleConstructorReturn(this, (SessionsRouter.__proto__ || Object.getPrototypeOf(SessionsRouter)).apply(this, arguments));
}
_createClass(SessionsRouter, [{
key: 'handleFind',
value: function handleFind(req) {
req.params.className = '_Session';
return _get(SessionsRouter.prototype.__proto__ || Object.getPrototypeOf(SessionsRouter.prototype), 'handleFind', this).call(this, req);
}
}, {
key: 'handleGet',
value: function handleGet(req) {
req.params.className = '_Session';
return _get(SessionsRouter.prototype.__proto__ || Object.getPrototypeOf(SessionsRouter.prototype), 'handleGet', this).call(this, req);
}
}, {
key: 'handleCreate',
value: function handleCreate(req) {
req.params.className = '_Session';
return _get(SessionsRouter.prototype.__proto__ || Object.getPrototypeOf(SessionsRouter.prototype), 'handleCreate', this).call(this, req);
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
req.params.className = '_Session';
return _get(SessionsRouter.prototype.__proto__ || Object.getPrototypeOf(SessionsRouter.prototype), 'handleUpdate', this).call(this, req);
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
req.params.className = '_Session';
return _get(SessionsRouter.prototype.__proto__ || Object.getPrototypeOf(SessionsRouter.prototype), 'handleDelete', this).call(this, req);
}
}, {
key: 'handleMe',
value: function handleMe(req) {
// TODO: Verify correct behavior
if (!req.info || !req.info.sessionToken) {
throw new _node2.default.Error(_node2.default.Error.INVALID_SESSION_TOKEN, 'Session token required.');
}
return _rest2.default.find(req.config, _Auth2.default.master(req.config), '_Session', { sessionToken: req.info.sessionToken }, undefined, req.info.clientSDK).then(function (response) {
if (!response.results || response.results.length == 0) {
throw new _node2.default.Error(_node2.default.Error.INVALID_SESSION_TOKEN, 'Session token not found.');
}
return {
response: response.results[0]
};
});
}
}, {
key: 'handleUpdateToRevocableSession',
value: function handleUpdateToRevocableSession(req) {
var config = req.config;
var masterAuth = _Auth2.default.master(config);
var user = req.auth.user;
// Issue #2720
// Calling without a session token would result in a not found user
if (!user) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'invalid session');
}
var expiresAt = config.generateSessionExpiresAt();
var sessionData = {
sessionToken: 'r:' + (0, _cryptoUtils.newToken)(),
user: {
__type: 'Pointer',
className: '_User',
objectId: user.id
},
createdWith: {
'action': 'upgrade'
},
restricted: false,
installationId: req.auth.installationId,
expiresAt: _node2.default._encode(expiresAt)
};
var create = new _RestWrite2.default(config, masterAuth, '_Session', null, sessionData);
return create.execute().then(function () {
// delete the session token, use the db to skip beforeSave
return config.database.update('_User', {
objectId: user.id
}, {
sessionToken: { __op: 'Delete' }
});
}).then(function () {
return Promise.resolve({ response: sessionData });
});
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/sessions/me', function (req) {
return _this2.handleMe(req);
});
this.route('GET', '/sessions', function (req) {
return _this2.handleFind(req);
});
this.route('GET', '/sessions/:objectId', function (req) {
return _this2.handleGet(req);
});
this.route('POST', '/sessions', function (req) {
return _this2.handleCreate(req);
});
this.route('PUT', '/sessions/:objectId', function (req) {
return _this2.handleUpdate(req);
});
this.route('DELETE', '/sessions/:objectId', function (req) {
return _this2.handleDelete(req);
});
this.route('POST', '/upgradeToRevocableSession', function (req) {
return _this2.handleUpdateToRevocableSession(req);
});
}
}]);
return SessionsRouter;
}(_ClassesRouter3.default);
exports.default = SessionsRouter;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 9 1 1 1 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UsersRouter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; Eif ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { Eif (protoProps) defineProperties(Constructor.prototype, protoProps); Iif (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _deepcopy = require('deepcopy');
var _deepcopy2 = _interopRequireDefault(_deepcopy);
var _node = require('parse/node');
var _node2 = _interopRequireDefault(_node);
var _Config = require('../Config');
var _Config2 = _interopRequireDefault(_Config);
var _AccountLockout = require('../AccountLockout');
var _AccountLockout2 = _interopRequireDefault(_AccountLockout);
var _ClassesRouter2 = require('./ClassesRouter');
var _ClassesRouter3 = _interopRequireDefault(_ClassesRouter2);
var _rest = require('../rest');
var _rest2 = _interopRequireDefault(_rest);
var _Auth = require('../Auth');
var _Auth2 = _interopRequireDefault(_Auth);
var _password = require('../password');
var _password2 = _interopRequireDefault(_password);
var _RestWrite = require('../RestWrite');
var _RestWrite2 = _interopRequireDefault(_RestWrite);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // These methods handle the User-related routes.
var cryptoUtils = require('../cryptoUtils');
var UsersRouter = exports.UsersRouter = function (_ClassesRouter) {
_inherits(UsersRouter, _ClassesRouter);
function UsersRouter() {
_classCallCheck(this, UsersRouter);
return _possibleConstructorReturn(this, (UsersRouter.__proto__ || Object.getPrototypeOf(UsersRouter)).apply(this, arguments));
}
_createClass(UsersRouter, [{
key: 'handleFind',
value: function handleFind(req) {
req.params.className = '_User';
return _get(UsersRouter.prototype.__proto__ || Object.getPrototypeOf(UsersRouter.prototype), 'handleFind', this).call(this, req);
}
}, {
key: 'handleGet',
value: function handleGet(req) {
req.params.className = '_User';
return _get(UsersRouter.prototype.__proto__ || Object.getPrototypeOf(UsersRouter.prototype), 'handleGet', this).call(this, req);
}
}, {
key: 'handleCreate',
value: function handleCreate(req) {
var data = (0, _deepcopy2.default)(req.body);
req.body = data;
req.params.className = '_User';
return _get(UsersRouter.prototype.__proto__ || Object.getPrototypeOf(UsersRouter.prototype), 'handleCreate', this).call(this, req);
}
}, {
key: 'handleUpdate',
value: function handleUpdate(req) {
req.params.className = '_User';
return _get(UsersRouter.prototype.__proto__ || Object.getPrototypeOf(UsersRouter.prototype), 'handleUpdate', this).call(this, req);
}
}, {
key: 'handleDelete',
value: function handleDelete(req) {
req.params.className = '_User';
return _get(UsersRouter.prototype.__proto__ || Object.getPrototypeOf(UsersRouter.prototype), 'handleDelete', this).call(this, req);
}
}, {
key: 'handleMe',
value: function handleMe(req) {
if (!req.info || !req.info.sessionToken) {
throw new _node2.default.Error(_node2.default.Error.INVALID_SESSION_TOKEN, 'invalid session token');
}
var sessionToken = req.info.sessionToken;
return _rest2.default.find(req.config, _Auth2.default.master(req.config), '_Session', { sessionToken: sessionToken }, { include: 'user' }, req.info.clientSDK).then(function (response) {
if (!response.results || response.results.length == 0 || !response.results[0].user) {
throw new _node2.default.Error(_node2.default.Error.INVALID_SESSION_TOKEN, 'invalid session token');
} else {
var user = response.results[0].user;
// Send token back on the login, because SDKs expect that.
user.sessionToken = sessionToken;
return { response: user };
}
});
}
}, {
key: 'handleLogIn',
value: function handleLogIn(req) {
// Use query parameters instead if provided in url
if (!req.body.username && req.query.username) {
req.body = req.query;
}
// TODO: use the right error codes / descriptions.
if (!req.body.username) {
throw new _node2.default.Error(_node2.default.Error.USERNAME_MISSING, 'username is required.');
}
if (!req.body.password) {
throw new _node2.default.Error(_node2.default.Error.PASSWORD_MISSING, 'password is required.');
}
if (typeof req.body.username !== 'string' || typeof req.body.password !== 'string') {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}
var user = void 0;
var isValidPassword = false;
return req.config.database.find('_User', { username: req.body.username }).then(function (results) {
if (!results.length) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}
user = results[0];
if (req.config.verifyUserEmails && req.config.preventLoginWithUnverifiedEmail && !user.emailVerified) {
throw new _node2.default.Error(_node2.default.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
}
return _password2.default.compare(req.body.password, user.password);
}).then(function (correct) {
isValidPassword = correct;
var accountLockoutPolicy = new _AccountLockout2.default(user, req.config);
return accountLockoutPolicy.handleLoginAttempt(isValidPassword);
}).then(function () {
if (!isValidPassword) {
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}
// handle password expiry policy
if (req.config.passwordPolicy && req.config.passwordPolicy.maxPasswordAge) {
var changedAt = user._password_changed_at;
if (!changedAt) {
// password was created before expiry policy was enabled.
// simply update _User object so that it will start enforcing from now
changedAt = new Date();
req.config.database.update('_User', { username: user.username }, { _password_changed_at: _node2.default._encode(changedAt) });
} else {
// check whether the password has expired
if (changedAt.__type == 'Date') {
changedAt = new Date(changedAt.iso);
}
// Calculate the expiry time.
var _expiresAt = new Date(changedAt.getTime() + 86400000 * req.config.passwordPolicy.maxPasswordAge);
if (_expiresAt < new Date()) // fail of current time is past password expiry time
throw new _node2.default.Error(_node2.default.Error.OBJECT_NOT_FOUND, 'Your password has expired. Please reset your password.');
}
}
var token = 'r:' + cryptoUtils.newToken();
user.sessionToken = token;
delete user.password;
// Sometimes the authData still has null on that keys
// https://github.com/ParsePlatform/parse-server/issues/935
if (user.authData) {
Object.keys(user.authData).forEach(function (provider) {
if (user.authData[provider] === null) {
delete user.authData[provider];
}
});
if (Object.keys(user.authData).length == 0) {
delete user.authData;
}
}
req.config.filesController.expandFilesInObject(req.config, user);
var expiresAt = req.config.generateSessionExpiresAt();
var sessionData = {
sessionToken: token,
user: {
__type: 'Pointer',
className: '_User',
objectId: user.objectId
},
createdWith: {
'action': 'login',
'authProvider': 'password'
},
restricted: false,
expiresAt: _node2.default._encode(expiresAt)
};
if (req.info.installationId) {
sessionData.installationId = req.info.installationId;
}
var create = new _RestWrite2.default(req.config, _Auth2.default.master(req.config), '_Session', null, sessionData);
return create.execute();
}).then(function () {
return { response: user };
});
}
}, {
key: 'handleLogOut',
value: function handleLogOut(req) {
var success = { response: {} };
if (req.info && req.info.sessionToken) {
return _rest2.default.find(req.config, _Auth2.default.master(req.config), '_Session', { sessionToken: req.info.sessionToken }, undefined, req.info.clientSDK).then(function (records) {
if (records.results && records.results.length) {
return _rest2.default.del(req.config, _Auth2.default.master(req.config), '_Session', records.results[0].objectId).then(function () {
return Promise.resolve(success);
});
}
return Promise.resolve(success);
});
}
return Promise.resolve(success);
}
}, {
key: '_throwOnBadEmailConfig',
value: function _throwOnBadEmailConfig(req) {
try {
_Config2.default.validateEmailConfiguration({
emailAdapter: req.config.userController.adapter,
appName: req.config.appName,
publicServerURL: req.config.publicServerURL,
emailVerifyTokenValidityDuration: req.config.emailVerifyTokenValidityDuration
});
} catch (e) {
if (typeof e === 'string') {
// Maybe we need a Bad Configuration error, but the SDKs won't understand it. For now, Internal Server Error.
throw new _node2.default.Error(_node2.default.Error.INTERNAL_SERVER_ERROR, 'An appName, publicServerURL, and emailAdapter are required for password reset and email verification functionality.');
} else {
throw e;
}
}
}
}, {
key: 'handleResetRequest',
value: function handleResetRequest(req) {
this._throwOnBadEmailConfig(req);
var email = req.body.email;
if (!email) {
throw new _node2.default.Error(_node2.default.Error.EMAIL_MISSING, "you must provide an email");
}
if (typeof email !== 'string') {
throw new _node2.default.Error(_node2.default.Error.INVALID_EMAIL_ADDRESS, 'you must provide a valid email string');
}
var userController = req.config.userController;
return userController.sendPasswordResetEmail(email).then(function () {
return Promise.resolve({
response: {}
});
}, function (err) {
if (err.code === _node2.default.Error.OBJECT_NOT_FOUND) {
throw new _node2.default.Error(_node2.default.Error.EMAIL_NOT_FOUND, 'No user found with email ' + email + '.');
} else {
throw err;
}
});
}
}, {
key: 'handleVerificationEmailRequest',
value: function handleVerificationEmailRequest(req) {
this._throwOnBadEmailConfig(req);
var email = req.body.email;
if (!email) {
throw new _node2.default.Error(_node2.default.Error.EMAIL_MISSING, 'you must provide an email');
}
if (typeof email !== 'string') {
throw new _node2.default.Error(_node2.default.Error.INVALID_EMAIL_ADDRESS, 'you must provide a valid email string');
}
return req.config.database.find('_User', { email: email }).then(function (results) {
if (!results.length || results.length < 1) {
throw new _node2.default.Error(_node2.default.Error.EMAIL_NOT_FOUND, 'No user found with email ' + email);
}
var user = results[0];
if (user.emailVerified) {
throw new _node2.default.Error(_node2.default.Error.OTHER_CAUSE, 'Email ' + email + ' is already verified.');
}
var userController = req.config.userController;
userController.sendVerificationEmail(user);
return { response: {} };
});
}
}, {
key: 'mountRoutes',
value: function mountRoutes() {
var _this2 = this;
this.route('GET', '/users', function (req) {
return _this2.handleFind(req);
});
this.route('POST', '/users', function (req) {
return _this2.handleCreate(req);
});
this.route('GET', '/users/me', function (req) {
return _this2.handleMe(req);
});
this.route('GET', '/users/:objectId', function (req) {
return _this2.handleGet(req);
});
this.route('PUT', '/users/:objectId', function (req) {
return _this2.handleUpdate(req);
});
this.route('DELETE', '/users/:objectId', function (req) {
return _this2.handleDelete(req);
});
this.route('GET', '/login', function (req) {
return _this2.handleLogIn(req);
});
this.route('POST', '/logout', function (req) {
return _this2.handleLogOut(req);
});
this.route('POST', '/requestPasswordReset', function (req) {
return _this2.handleResetRequest(req);
});
this.route('POST', '/verificationEmailRequest', function (req) {
return _this2.handleVerificationEmailRequest(req);
});
}
}]);
return UsersRouter;
}(_ClassesRouter3.default);
exports.default = UsersRouter;
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| parse-live-query-server.js | 100% | (15 / 15) | 100% | (4 / 4) | 100% | (2 / 2) | 100% | (14 / 14) | |
| parse-server.js | 51.96% | (53 / 102) | 29.73% | (11 / 37) | 33.33% | (4 / 12) | 51.49% | (52 / 101) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 1 1 1 1 1 1 1 3 1 1 1 1 1 1 | 'use strict';
var _parseLiveQueryServer = require('./definitions/parse-live-query-server');
var _parseLiveQueryServer2 = _interopRequireDefault(_parseLiveQueryServer);
var _runner = require('./utils/runner');
var _runner2 = _interopRequireDefault(_runner);
var _index = require('../index');
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
(0, _runner2.default)({
definitions: _parseLiveQueryServer2.default,
start: function start(program, options, logOptions) {
logOptions();
var app = (0, _express2.default)();
var httpServer = require('http').createServer(app);
httpServer.listen(options.port);
_index.ParseServer.createLiveQueryServer(httpServer, options);
}
});
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 2 2 2 2 2 2 2 2 2 2 2 10 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 | 'use strict';
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
var _index = require('../index');
var _parseServer = require('./definitions/parse-server');
var _parseServer2 = _interopRequireDefault(_parseServer);
var _cluster = require('cluster');
var _cluster2 = _interopRequireDefault(_cluster);
var _os = require('os');
var _os2 = _interopRequireDefault(_os);
var _runner = require('./utils/runner');
var _runner2 = _interopRequireDefault(_runner);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
var path = require("path");
var help = function help() {
console.log(' Get Started guide:');
console.log('');
console.log(' Please have a look at the get started guide!');
console.log(' https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide');
console.log('');
console.log('');
console.log(' Usage with npm start');
console.log('');
console.log(' $ npm start -- path/to/config.json');
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log('');
console.log('');
console.log(' Usage:');
console.log('');
console.log(' $ parse-server path/to/config.json');
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log('');
};
function startServer(options, callback) {
var app = (0, _express2.default)();
Iif (options.middleware) {
var middleware = void 0;
if (typeof options.middleware == 'function') {
middleware = options.middleware;
}if (typeof options.middleware == 'string') {
middleware = require(path.resolve(process.cwd(), options.middleware));
} else {
throw "middleware should be a string or a function";
}
app.use(middleware);
}
var api = new _index.ParseServer(options);
var sockets = {};
app.use(options.mountPath, api);
var server = app.listen(options.port, options.host, callback);
server.on('connection', initializeConnections);
if (options.startLiveQueryServer || options.liveQueryServerOptions) {
var liveQueryServer = server;
if (options.liveQueryPort) {
liveQueryServer = (0, _express2.default)().listen(options.liveQueryPort, function () {
console.log('ParseLiveQuery listening on ' + options.liveQueryPort);
});
}
_index.ParseServer.createLiveQueryServer(liveQueryServer, options.liveQueryServerOptions);
}
function initializeConnections(socket) {
/* Currently, express doesn't shut down immediately after receiving SIGINT/SIGTERM if it has client connections that haven't timed out. (This is a known issue with node - https://github.com/nodejs/node/issues/2642)
This function, along with `destroyAliveConnections()`, intend to fix this behavior such that parse server will close all open connections and initiate the shutdown process as soon as it receives a SIGINT/SIGTERM signal. */
var socketId = socket.remoteAddress + ':' + socket.remotePort;
sockets[socketId] = socket;
socket.on('close', function () {
delete sockets[socketId];
});
}
function destroyAliveConnections() {
for (var socketId in sockets) {
try {
sockets[socketId].destroy();
} catch (e) {/* */}
}
}
var handleShutdown = function handleShutdown() {
console.log('Termination signal received. Shutting down.');
destroyAliveConnections();
server.close();
};
process.on('SIGTERM', handleShutdown);
process.on('SIGINT', handleShutdown);
}
(0, _runner2.default)({
definitions: _parseServer2.default,
help: help,
usage: '[options] <path/to/configuration.json>',
start: function start(program, options, logOptions) {
Eif (!options.serverURL) {
options.serverURL = 'http://localhost:' + options.port + options.mountPath;
}
Eif (!options.appId || !options.masterKey || !options.serverURL) {
program.outputHelp();
console.error("");
console.error('\x1B[31mERROR: appId and masterKey are required\x1B[0m');
console.error("");
process.exit(1);
}
Iif (options["liveQuery.classNames"]) {
options.liveQuery = options.liveQuery || {};
options.liveQuery.classNames = options["liveQuery.classNames"];
delete options["liveQuery.classNames"];
}
Iif (options["liveQuery.redisURL"]) {
options.liveQuery = options.liveQuery || {};
options.liveQuery.redisURL = options["liveQuery.redisURL"];
delete options["liveQuery.redisURL"];
}
Iif (options.cluster) {
var numCPUs = typeof options.cluster === 'number' ? options.cluster : _os2.default.cpus().length;
if (_cluster2.default.isMaster) {
logOptions();
for (var i = 0; i < numCPUs; i++) {
_cluster2.default.fork();
}
_cluster2.default.on('exit', function (worker, code) {
console.log('worker ' + worker.process.pid + ' died (' + code + ')... Restarting');
_cluster2.default.fork();
});
} else {
startServer(options, function () {
console.log('[' + process.pid + '] parse-server running on ' + options.serverURL);
});
}
} else {
startServer(options, function () {
logOptions();
console.log('');
console.log('[' + process.pid + '] parse-server running on ' + options.serverURL);
});
}
}
});
/* eslint-enable no-console */
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| parse-live-query-server.js | 100% | (3 / 3) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (3 / 3) | |
| parse-server.js | 75% | (3 / 4) | 100% | (0 / 0) | 0% | (0 / 1) | 75% | (3 / 4) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _parsers = require("../utils/parsers");
exports.default = {
"appId": {
required: true,
help: "Required. This string should match the appId in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same appId."
},
"masterKey": {
required: true,
help: "Required. This string should match the masterKey in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same masterKey."
},
"serverURL": {
required: true,
help: "Required. This string should match the serverURL in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same serverURL."
},
"redisURL": {
help: "Optional. This string should match the masterKey in use by your Parse Server. If you deploy the LiveQuery server alongside Parse Server, the LiveQuery server will try to use the same masterKey."
},
"keyPairs": {
help: "Optional. A JSON object that serves as a whitelist of keys. It is used for validating clients when they try to connect to the LiveQuery server. Check the following Security section and our protocol specification for details."
},
"websocketTimeout": {
help: "Optional. Number of milliseconds between ping/pong frames. The WebSocket server sends ping/pong frames to the clients to keep the WebSocket alive. This value defines the interval of the ping/pong frame from the server to clients. Defaults to 10 * 1000 ms (10 s).",
action: (0, _parsers.numberParser)("websocketTimeout")
},
"cacheTimeout": {
help: "Optional. Number in milliseconds. When clients provide the sessionToken to the LiveQuery server, the LiveQuery server will try to fetch its ParseUser's objectId from parse server and store it in the cache. The value defines the duration of the cache. Check the following Security section and our protocol specification for details. Defaults to 30 * 24 * 60 * 60 * 1000 ms (~30 days).",
action: (0, _parsers.numberParser)("cacheTimeout")
},
"logLevel": {
help: "Optional. This string defines the log level of the LiveQuery server. We support VERBOSE, INFO, ERROR, NONE. Defaults to INFO."
},
"port": {
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: (0, _parsers.numberParser)("port")
}
};
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _parsers = require("../utils/parsers");
exports.default = {
"appId": {
env: "PARSE_SERVER_APPLICATION_ID",
help: "Your Parse Application ID",
required: true
},
"masterKey": {
env: "PARSE_SERVER_MASTER_KEY",
help: "Your Parse Master Key",
required: true
},
"port": {
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: (0, _parsers.numberParser)("port")
},
"host": {
env: "PARSE_SERVER_HOST",
help: "The host to serve ParseServer on. defaults to 0.0.0.0",
default: '0.0.0.0'
},
"databaseURI": {
env: "PARSE_SERVER_DATABASE_URI",
help: "The full URI to your mongodb database"
},
"databaseOptions": {
env: "PARSE_SERVER_DATABASE_OPTIONS",
help: "Options to pass to the mongodb client",
action: _parsers.objectParser
},
"collectionPrefix": {
env: "PARSE_SERVER_COLLECTION_PREFIX",
help: 'A collection prefix for the classes'
},
"serverURL": {
env: "PARSE_SERVER_URL",
help: "URL to your parse server with http:// or https://."
},
"publicServerURL": {
env: "PARSE_PUBLIC_SERVER_URL",
help: "Public URL to your parse server with http:// or https://."
},
"clientKey": {
env: "PARSE_SERVER_CLIENT_KEY",
help: "Key for iOS, MacOS, tvOS clients"
},
"javascriptKey": {
env: "PARSE_SERVER_JAVASCRIPT_KEY",
help: "Key for the Javascript SDK"
},
"restAPIKey": {
env: "PARSE_SERVER_REST_API_KEY",
help: "Key for REST calls"
},
"dotNetKey": {
env: "PARSE_SERVER_DOT_NET_KEY",
help: "Key for Unity and .Net SDK"
},
"webhookKey": {
env: "PARSE_SERVER_WEBHOOK_KEY",
help: "Key sent with outgoing webhook calls"
},
"cloud": {
env: "PARSE_SERVER_CLOUD_CODE_MAIN",
help: "Full path to your cloud code main.js"
},
"push": {
env: "PARSE_SERVER_PUSH",
help: "Configuration for push, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Push",
action: _parsers.objectParser
},
"oauth": {
env: "PARSE_SERVER_OAUTH_PROVIDERS",
help: "[DEPRECATED (use auth option)] Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
action: _parsers.objectParser
},
"auth": {
env: "PARSE_SERVER_AUTH_PROVIDERS",
help: "Configuration for your authentication providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
action: _parsers.objectParser
},
"fileKey": {
env: "PARSE_SERVER_FILE_KEY",
help: "Key for your files"
},
"facebookAppIds": {
env: "PARSE_SERVER_FACEBOOK_APP_IDS",
help: "[DEPRECATED (use auth option)]",
action: function action() {
throw 'facebookAppIds is deprecated, please use { auth: \
{facebook: \
{ appIds: [] } \
}\
}\
}';
}
},
"enableAnonymousUsers": {
env: "PARSE_SERVER_ENABLE_ANON_USERS",
help: "Enable (or disable) anon users, defaults to true",
action: _parsers.booleanParser
},
"allowClientClassCreation": {
env: "PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION",
help: "Enable (or disable) client class creation, defaults to true",
action: _parsers.booleanParser
},
"mountPath": {
env: "PARSE_SERVER_MOUNT_PATH",
help: "Mount path for the server, defaults to /parse",
default: "/parse"
},
"filesAdapter": {
env: "PARSE_SERVER_FILES_ADAPTER",
help: "Adapter module for the files sub-system",
action: _parsers.moduleOrObjectParser
},
"emailAdapter": {
env: "PARSE_SERVER_EMAIL_ADAPTER",
help: "Adapter module for the email sending",
action: _parsers.moduleOrObjectParser
},
"verifyUserEmails": {
env: "PARSE_SERVER_VERIFY_USER_EMAILS",
help: "Enable (or disable) user email validation, defaults to false",
action: _parsers.booleanParser
},
"preventLoginWithUnverifiedEmail": {
env: "PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL",
help: "Prevent user from login if email is not verified and PARSE_SERVER_VERIFY_USER_EMAILS is true, defaults to false",
action: _parsers.booleanParser
},
"emailVerifyTokenValidityDuration": {
env: "PARSE_SERVER_EMAIL_VERIFY_TOKEN_VALIDITY_DURATION",
help: "Email verification token validity duration",
action: (0, _parsers.numberParser)("emailVerifyTokenValidityDuration")
},
"accountLockout": {
env: "PARSE_SERVER_ACCOUNT_LOCKOUT",
help: "account lockout policy for failed login attempts",
action: _parsers.objectParser
},
"passwordPolicy": {
env: "PARSE_SERVER_PASSWORD_POLICY",
help: "Password policy for enforcing password related rules",
action: _parsers.objectParser
},
"appName": {
env: "PARSE_SERVER_APP_NAME",
help: "Sets the app name"
},
"loggerAdapter": {
env: "PARSE_SERVER_LOGGER_ADAPTER",
help: "Adapter module for the logging sub-system",
action: _parsers.moduleOrObjectParser
},
"customPages": {
env: "PARSE_SERVER_CUSTOM_PAGES",
help: "custom pages for password validation and reset",
action: _parsers.objectParser
},
"maxUploadSize": {
env: "PARSE_SERVER_MAX_UPLOAD_SIZE",
help: "Max file size for uploads.",
default: "20mb"
},
"userSensitiveFields": {
help: "Personally identifiable information fields in the user table the should be removed for non-authorized users.",
default: ["email"]
},
"sessionLength": {
env: "PARSE_SERVER_SESSION_LENGTH",
help: "Session duration, defaults to 1 year",
action: (0, _parsers.numberParser)("sessionLength")
},
"verbose": {
env: "VERBOSE",
help: "Set the logging to verbose"
},
"jsonLogs": {
env: "JSON_LOGS",
help: "Log as structured JSON objects"
},
"logLevel": {
env: "PARSE_SERVER_LOG_LEVEL",
help: "Sets the level for logs"
},
"logsFolder": {
env: "PARSE_SERVER_LOGS_FOLDER",
help: "Folder for the logs (defaults to './logs'); set to null to disable file based logging",
action: _parsers.nullParser
},
"silent": {
help: "Disables console output"
},
"revokeSessionOnPasswordReset": {
env: "PARSE_SERVER_REVOKE_SESSION_ON_PASSWORD_RESET",
help: "When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.",
action: _parsers.booleanParser
},
"schemaCacheTTL": {
env: "PARSE_SERVER_SCHEMA_CACHE_TTL",
help: "The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 0; disabled.",
action: (0, _parsers.numberParser)("schemaCacheTTL")
},
"enableSingleSchemaCache": {
env: "PARSE_SERVER_ENABLE_SINGLE_SCHEMA_CACHE",
help: "Use a single schema cache shared across requests. Reduces number of queries made to _SCHEMA. Defaults to false, i.e. unique schema cache per request.",
action: _parsers.booleanParser
},
"cluster": {
env: "PARSE_SERVER_CLUSTER",
help: "Run with cluster, optionally set the number of processes default to os.cpus().length",
action: (0, _parsers.numberOrBoolParser)("cluster")
},
"liveQuery": {
env: "PARSE_SERVER_LIVE_QUERY_OPTIONS",
help: "parse-server's LiveQuery configuration object",
action: _parsers.objectParser
},
"liveQuery.classNames": {
help: "parse-server's LiveQuery classNames",
action: _parsers.arrayParser
},
"liveQuery.redisURL": {
help: "parse-server's LiveQuery redisURL"
},
"startLiveQueryServer": {
help: "Starts the liveQuery server",
action: _parsers.booleanParser
},
"liveQueryPort": {
help: 'Specific port to start the live query server',
action: (0, _parsers.numberParser)("liveQueryPort")
},
"liveQueryServerOptions": {
help: "Live query server configuration options (will start the liveQuery server)",
action: _parsers.objectParser
},
"middleware": {
help: "middleware for express server, can be string or function"
}
};
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| commander.js | 78.65% | (70 / 89) | 54% | (27 / 50) | 84.21% | (16 / 19) | 79.07% | (68 / 86) | |
| parsers.js | 42% | (21 / 50) | 10.81% | (4 / 37) | 27.27% | (3 / 11) | 43.75% | (21 / 48) | |
| runner.js | 88.89% | (24 / 27) | 54.17% | (13 / 24) | 83.33% | (5 / 6) | 91.67% | (22 / 24) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | 1 229 1 1 1 1 1 1 1 1 3 3 113 113 113 7 106 3 113 11 113 3 113 113 113 113 89 113 3 5 5 5 220 5 1 3 3 89 3 3 3 3 3 89 1 3 3 3 1 9 9 14 5 1 1 3 3 3 3 3 3 1 3 3 113 11 113 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /* eslint-disable no-console */
var _commander = require('commander');
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _definitions = void 0;
var _reverseDefinitions = void 0;
var _defaults = void 0;
_commander.Command.prototype.loadDefinitions = function (definitions) {
_definitions = definitions;
Object.keys(definitions).reduce(function (program, opt) {
Eif (_typeof(definitions[opt]) == "object") {
var additionalOptions = definitions[opt];
if (additionalOptions.required === true) {
return program.option('--' + opt + ' <' + opt + '>', additionalOptions.help, additionalOptions.action);
} else {
return program.option('--' + opt + ' [' + opt + ']', additionalOptions.help, additionalOptions.action);
}
}
return program.option('--' + opt + ' [' + opt + ']');
}, this);
_defaults = Object.keys(definitions).reduce(function (defs, opt) {
if (_definitions[opt].default) {
defs[opt] = _definitions[opt].default;
}
return defs;
}, {});
_reverseDefinitions = Object.keys(definitions).reduce(function (object, key) {
var value = definitions[key];
Eif ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) == "object") {
value = value.env;
}
if (value) {
object[value] = key;
}
return object;
}, {});
/* istanbul ignore next */
this.on('--help', function () {
console.log(' Configure From Environment:');
console.log('');
Object.keys(_reverseDefinitions).forEach(function (key) {
console.log(' $ ' + key + '=\'' + _reverseDefinitions[key] + '\'');
});
console.log('');
});
};
function parseEnvironment() {
var env = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return Object.keys(_reverseDefinitions).reduce(function (options, key) {
if (env[key]) {
var originalKey = _reverseDefinitions[key];
var action = function action(option) {
return option;
};
Eif (_typeof(_definitions[originalKey]) === "object") {
action = _definitions[originalKey].action || action;
}
options[_reverseDefinitions[key]] = action(env[key]);
}
return options;
}, {});
}
function parseConfigFile(program) {
var options = {};
Iif (program.args.length > 0) {
var jsonPath = program.args[0];
jsonPath = _path2.default.resolve(jsonPath);
var jsonConfig = require(jsonPath);
if (jsonConfig.apps) {
if (jsonConfig.apps.length > 1) {
throw 'Multiple apps are not supported';
}
options = jsonConfig.apps[0];
} else {
options = jsonConfig;
}
Object.keys(options).forEach(function (key) {
var value = options[key];
if (!_definitions[key]) {
throw 'error: unknown option ' + key;
}
var action = _definitions[key].action;
if (action) {
options[key] = action(value);
}
});
console.log('Configuration loaded from ' + jsonPath);
}
return options;
}
_commander.Command.prototype.setValuesIfNeeded = function (options) {
var _this = this;
Object.keys(options).forEach(function (key) {
if (!_this.hasOwnProperty(key)) {
_this[key] = options[key];
}
});
};
_commander.Command.prototype._parse = _commander.Command.prototype.parse;
_commander.Command.prototype.parse = function (args, env) {
this._parse(args);
// Parse the environment first
var envOptions = parseEnvironment(env);
var fromFile = parseConfigFile(this);
// Load the env if not passed from command line
this.setValuesIfNeeded(envOptions);
// Load from file to override
this.setValuesIfNeeded(fromFile);
// Last set the defaults
this.setValuesIfNeeded(_defaults);
};
_commander.Command.prototype.getOptions = function () {
var _this2 = this;
return Object.keys(_definitions).reduce(function (options, key) {
if (typeof _this2[key] !== 'undefined') {
options[key] = _this2[key];
}
return options;
}, {});
};
exports.default = new _commander.Command();
/* eslint-enable no-console */
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 1 1 1 1 1 8 3 3 3 1 1 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.numberParser = numberParser;
exports.numberOrBoolParser = numberOrBoolParser;
exports.objectParser = objectParser;
exports.arrayParser = arrayParser;
exports.moduleOrObjectParser = moduleOrObjectParser;
exports.booleanParser = booleanParser;
exports.nullParser = nullParser;
function numberParser(key) {
return function (opt) {
var intOpt = parseInt(opt);
Iif (!Number.isInteger(intOpt)) {
throw new Error('Key ' + key + ' has invalid value ' + opt);
}
return intOpt;
};
}
function numberOrBoolParser(key) {
return function (opt) {
if (typeof opt === 'boolean') {
return opt;
}
if (opt === 'true') {
return true;
}
if (opt === 'false') {
return false;
}
return numberParser(key)(opt);
};
}
function objectParser(opt) {
if ((typeof opt === 'undefined' ? 'undefined' : _typeof(opt)) == 'object') {
return opt;
}
return JSON.parse(opt);
}
function arrayParser(opt) {
if (Array.isArray(opt)) {
return opt;
} else if (typeof opt === 'string') {
return opt.split(',');
} else {
throw new Error(opt + ' should be a comma separated string or an array');
}
}
function moduleOrObjectParser(opt) {
if ((typeof opt === 'undefined' ? 'undefined' : _typeof(opt)) == 'object') {
return opt;
}
try {
return JSON.parse(opt);
} catch (e) {/* */}
return opt;
}
function booleanParser(opt) {
if (opt == true || opt == 'true' || opt == '1') {
return true;
}
return false;
}
function nullParser(opt) {
if (opt == 'null') {
return null;
}
return opt;
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 3 3 3 2 3 2 3 3 3 1 1 1 1 1 1 1 1 1 1 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.default = function (_ref) {
var definitions = _ref.definitions,
help = _ref.help,
usage = _ref.usage,
start = _ref.start;
_commander2.default.loadDefinitions(definitions);
if (usage) {
_commander2.default.usage(usage);
}
if (help) {
_commander2.default.on('--help', help);
}
_commander2.default.parse(process.argv, process.env);
var options = _commander2.default.getOptions();
start(_commander2.default, options, function () {
logStartupOptions(options);
});
};
var _commander = require("./commander");
var _commander2 = _interopRequireDefault(_commander);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function logStartupOptions(options) {
for (var key in options) {
var value = options[key];
Iif (key == "masterKey") {
value = "***REDACTED***";
}
Iif ((typeof value === "undefined" ? "undefined" : _typeof(value)) === 'object') {
value = JSON.stringify(value);
}
/* eslint-disable no-console */
console.log(key + ": " + value);
/* eslint-enable no-console */
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| HTTPResponse.js | 13.89% | (5 / 36) | 9.38% | (3 / 32) | 0% | (0 / 7) | 15.63% | (5 / 32) | |
| Parse.Cloud.js | 41.18% | (21 / 51) | 21.43% | (3 / 14) | 7.69% | (1 / 13) | 45.24% | (19 / 42) | |
| httpRequest.js | 30% | (18 / 60) | 20.45% | (9 / 44) | 14.29% | (1 / 7) | 29.82% | (17 / 57) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 1 1 | 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var HTTPResponse = function HTTPResponse(response, body) {
var _this = this;
_classCallCheck(this, HTTPResponse);
var _text = void 0,
_data = void 0;
this.status = response.statusCode;
this.headers = response.headers || {};
this.cookies = this.headers["set-cookie"];
if (typeof body == 'string') {
_text = body;
} else if (Buffer.isBuffer(body)) {
this.buffer = body;
} else if ((typeof body === 'undefined' ? 'undefined' : _typeof(body)) == 'object') {
_data = body;
}
var getText = function getText() {
if (!_text && _this.buffer) {
_text = _this.buffer.toString('utf-8');
} else if (!_text && _data) {
_text = JSON.stringify(_data);
}
return _text;
};
var getData = function getData() {
if (!_data) {
try {
_data = JSON.parse(getText());
} catch (e) {/* */}
}
return _data;
};
Object.defineProperty(this, 'body', {
get: function get() {
return body;
}
});
Object.defineProperty(this, 'text', {
enumerable: true,
get: getText
});
Object.defineProperty(this, 'data', {
enumerable: true,
get: getData
});
};
exports.default = HTTPResponse;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 'use strict';
var _node = require('parse/node');
var _triggers = require('../triggers');
var triggers = _interopRequireWildcard(_triggers);
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function validateClassNameForTriggers(className) {
var restrictedClassNames = ['_Session'];
if (restrictedClassNames.indexOf(className) != -1) {
throw 'Triggers are not supported for ' + className + ' class.';
}
return className;
}
function getClassName(parseClass) {
if (parseClass && parseClass.className) {
return validateClassNameForTriggers(parseClass.className);
}
return validateClassNameForTriggers(parseClass);
}
var ParseCloud = {};
ParseCloud.define = function (functionName, handler, validationHandler) {
triggers.addFunction(functionName, handler, validationHandler, _node.Parse.applicationId);
};
ParseCloud.job = function (functionName, handler) {
triggers.addJob(functionName, handler, _node.Parse.applicationId);
};
ParseCloud.beforeSave = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.beforeSave, className, handler, _node.Parse.applicationId);
};
ParseCloud.beforeDelete = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.beforeDelete, className, handler, _node.Parse.applicationId);
};
ParseCloud.afterSave = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.afterSave, className, handler, _node.Parse.applicationId);
};
ParseCloud.afterDelete = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.afterDelete, className, handler, _node.Parse.applicationId);
};
ParseCloud.beforeFind = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.beforeFind, className, handler, _node.Parse.applicationId);
};
ParseCloud.afterFind = function (parseClass, handler) {
var className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.afterFind, className, handler, _node.Parse.applicationId);
};
ParseCloud._removeAllHooks = function () {
triggers._unregisterAll();
};
ParseCloud.useMasterKey = function () {
// eslint-disable-next-line
console.warn("Parse.Cloud.useMasterKey is deprecated (and has no effect anymore) on parse-server, please refer to the cloud code migration notes: https://github.com/ParsePlatform/parse-server/wiki/Compatibility-with-Hosted-Parse#cloud-code");
};
ParseCloud.httpRequest = require("./httpRequest");
module.exports = ParseCloud;
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 1 1 1 1 1 1 1 1 1 1 1 5 1 1 1 1 1 | 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _request = require('request'); var _request2 = _interopRequireDefault(_request); var _node = require('parse/node'); var _node2 = _interopRequireDefault(_node); var _HTTPResponse = require('./HTTPResponse'); var _HTTPResponse2 = _interopRequireDefault(_HTTPResponse); var _querystring = require('querystring'); var _querystring2 = _interopRequireDefault(_querystring); var _logger = require('../logger'); var _logger2 = _interopRequireDefault(_logger); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var encodeBody = function encodeBody(_ref) { var body = _ref.body, _ref$headers = _ref.headers, headers = _ref$headers === undefined ? {} : _ref$headers; if ((typeof body === 'undefined' ? 'undefined' : _typeof(body)) !== 'object') { return { body: body, headers: headers }; } var contentTypeKeys = Object.keys(headers).filter(function (key) { return key.match(/content-type/i) != null; }); if (contentTypeKeys.length == 0) { // no content type // As per https://parse.com/docs/cloudcode/guide#cloud-code-advanced-sending-a-post-request the default encoding is supposedly x-www-form-urlencoded body = _querystring2.default.stringify(body); headers['Content-Type'] = 'application/x-www-form-urlencoded'; } else { /* istanbul ignore next */ if (contentTypeKeys.length > 1) { _logger2.default.error('Parse.Cloud.httpRequest', 'multiple content-type headers are set.'); } // There maybe many, we'll just take the 1st one var contentType = contentTypeKeys[0]; if (headers[contentType].match(/application\/json/i)) { body = JSON.stringify(body); } else if (headers[contentType].match(/application\/x-www-form-urlencoded/i)) { body = _querystring2.default.stringify(body); } } return { body: body, headers: headers }; }; module.exports = function (options) { var promise = new _node2.default.Promise(); var callbacks = { success: options.success, error: options.error }; delete options.success; delete options.error; delete options.uri; // not supported options = Object.assign(options, encodeBody(options)); // set follow redirects to false by default options.followRedirect = options.followRedirects == true; // support params options if (_typeof(options.params) === 'object') { options.qs = options.params; } else if (typeof options.params === 'string') { options.qs = _querystring2.default.parse(options.params); } // force the response as a buffer options.encoding = null; (0, _request2.default)(options, function (error, response, body) { if (error) { if (callbacks.error) { callbacks.error(error); } return promise.reject(error); } var httpResponse = new _HTTPResponse2.default(response, body); // Consider <200 && >= 400 as errors if (httpResponse.status < 200 || httpResponse.status >= 400) { if (callbacks.error) { callbacks.error(httpResponse); } return promise.reject(httpResponse); } else { if (callbacks.success) { callbacks.success(httpResponse); } return promise.resolve(httpResponse); } }); return promise; }; module.exports.encodeBody = encodeBody; |
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| mongodbUrl.js | 97.52% | (550 / 564) | 98.75% | (551 / 558) | 81.25% | (13 / 16) | 97.6% | (488 / 500) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 256 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | // A slightly patched version of node's url module, with support for mongodb:// // uris. // // See https://github.com/nodejs/node/blob/master/LICENSE for licensing // information 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var punycode = require('punycode'); exports.parse = urlParse; exports.resolve = urlResolve; exports.resolveObject = urlResolveObject; exports.format = urlFormat; exports.Url = Url; function Url() { this.protocol = null; this.slashes = null; this.auth = null; this.host = null; this.port = null; this.hostname = null; this.hash = null; this.search = null; this.query = null; this.pathname = null; this.path = null; this.href = null; } // Reference: RFC 3986, RFC 1808, RFC 2396 // define these here so at least they only have to be // compiled once on the first module load. var protocolPattern = /^([a-z0-9.+-]+:)/i; var portPattern = /:[0-9]*$/; // Special case for a simple path URL var simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/; var hostnameMaxLen = 255; // protocols that can allow "unsafe" and "unwise" chars. var unsafeProtocol = { 'javascript': true, 'javascript:': true }; // protocols that never have a hostname. var hostlessProtocol = { 'javascript': true, 'javascript:': true }; // protocols that always contain a // bit. var slashedProtocol = { 'http': true, 'http:': true, 'https': true, 'https:': true, 'ftp': true, 'ftp:': true, 'gopher': true, 'gopher:': true, 'file': true, 'file:': true }; var querystring = require('querystring'); /* istanbul ignore next: improve coverage */ function urlParse(url, parseQueryString, slashesDenoteHost) { if (url instanceof Url) return url; var u = new Url(); u.parse(url, parseQueryString, slashesDenoteHost); return u; } /* istanbul ignore next: improve coverage */ Url.prototype.parse = function (url, parseQueryString, slashesDenoteHost) { if (typeof url !== 'string') { throw new TypeError('Parameter "url" must be a string, not ' + (typeof url === 'undefined' ? 'undefined' : _typeof(url))); } // Copy chrome, IE, opera backslash-handling behavior. // Back slashes before the query string get converted to forward slashes // See: https://code.google.com/p/chromium/issues/detail?id=25916 var hasHash = false; var start = -1; var end = -1; var rest = ''; var lastPos = 0; var i = 0; for (var inWs = false, split = false; i < url.length; ++i) { var code = url.charCodeAt(i); // Find first and last non-whitespace characters for trimming var isWs = code === 32 /* */ || code === 9 /*\t*/ || code === 13 /*\r*/ || code === 10 /*\n*/ || code === 12 /*\f*/ || code === 160 /*\u00A0*/ || code === 65279 /*\uFEFF*/; if (start === -1) { if (isWs) continue; lastPos = start = i; } else { if (inWs) { if (!isWs) { end = -1; inWs = false; } } else if (isWs) { end = i; inWs = true; } } // Only convert backslashes while we haven't seen a split character if (!split) { switch (code) { case 35: // '#' hasHash = true; // Fall through case 63: // '?' split = true; break; case 92: // '\\' if (i - lastPos > 0) rest += url.slice(lastPos, i); rest += '/'; lastPos = i + 1; break; } } else if (!hasHash && code === 35 /*#*/) { hasHash = true; } } // Check if string was non-empty (including strings with only whitespace) if (start !== -1) { if (lastPos === start) { // We didn't convert any backslashes if (end === -1) { if (start === 0) rest = url;else rest = url.slice(start); } else { rest = url.slice(start, end); } } else if (end === -1 && lastPos < url.length) { // We converted some backslashes and have only part of the entire string rest += url.slice(lastPos); } else if (end !== -1 && lastPos < end) { // We converted some backslashes and have only part of the entire string rest += url.slice(lastPos, end); } } if (!slashesDenoteHost && !hasHash) { // Try fast path regexp var simplePath = simplePathPattern.exec(rest); if (simplePath) { this.path = rest; this.href = rest; this.pathname = simplePath[1]; if (simplePath[2]) { this.search = simplePath[2]; if (parseQueryString) { this.query = querystring.parse(this.search.slice(1)); } else { this.query = this.search.slice(1); } } else if (parseQueryString) { this.search = ''; this.query = {}; } return this; } } var proto = protocolPattern.exec(rest); if (proto) { proto = proto[0]; var lowerProto = proto.toLowerCase(); this.protocol = lowerProto; rest = rest.slice(proto.length); } // figure out if it's got a host // user@server is *always* interpreted as a hostname, and url // resolution will treat //foo/bar as host=foo,path=bar because that's // how the browser resolves relative URLs. if (slashesDenoteHost || proto || /^\/\/[^@\/]+@[^@\/]+/.test(rest)) { var slashes = rest.charCodeAt(0) === 47 /*/*/ && rest.charCodeAt(1) === 47 /*/*/; if (slashes && !(proto && hostlessProtocol[proto])) { rest = rest.slice(2); this.slashes = true; } } if (!hostlessProtocol[proto] && (slashes || proto && !slashedProtocol[proto])) { // there's a hostname. // the first instance of /, ?, ;, or # ends the host. // // If there is an @ in the hostname, then non-host chars *are* allowed // to the left of the last @ sign, unless some host-ending character // comes *before* the @-sign. // URLs are obnoxious. // // ex: // http://a@b@c/ => user:a@b host:c // http://a@b?@c => user:a host:b path:/?@c // v0.12 TODO(isaacs): This is not quite how Chrome does things. // Review our test case against browsers more comprehensively. var hostEnd = -1; var atSign = -1; var nonHost = -1; for (i = 0; i < rest.length; ++i) { switch (rest.charCodeAt(i)) { case 9: // '\t' case 10: // '\n' case 13: // '\r' case 32: // ' ' case 34: // '"' case 37: // '%' case 39: // '\'' case 59: // ';' case 60: // '<' case 62: // '>' case 92: // '\\' case 94: // '^' case 96: // '`' case 123: // '{' case 124: // '|' case 125: // '}' // Characters that are never ever allowed in a hostname from RFC 2396 if (nonHost === -1) nonHost = i; break; case 35: // '#' case 47: // '/' case 63: // '?' // Find the first instance of any host-ending characters if (nonHost === -1) nonHost = i; hostEnd = i; break; case 64: // '@' // At this point, either we have an explicit point where the // auth portion cannot go past, or the last @ char is the decider. atSign = i; nonHost = -1; break; } if (hostEnd !== -1) break; } start = 0; if (atSign !== -1) { this.auth = decodeURIComponent(rest.slice(0, atSign)); start = atSign + 1; } if (nonHost === -1) { this.host = rest.slice(start); rest = ''; } else { this.host = rest.slice(start, nonHost); rest = rest.slice(nonHost); } // pull out port. this.parseHost(); // we've indicated that there is a hostname, // so even if it's empty, it has to be present. if (typeof this.hostname !== 'string') this.hostname = ''; var hostname = this.hostname; // if hostname begins with [ and ends with ] // assume that it's an IPv6 address. var ipv6Hostname = hostname.charCodeAt(0) === 91 /*[*/ && hostname.charCodeAt(hostname.length - 1) === 93 /*]*/; // validate a little. if (!ipv6Hostname) { var result = validateHostname(this, rest, hostname); if (result !== undefined) rest = result; } if (this.hostname.length > hostnameMaxLen) { this.hostname = ''; } else { // hostnames are always lower case. this.hostname = this.hostname.toLowerCase(); } if (!ipv6Hostname) { // IDNA Support: Returns a punycoded representation of "domain". // It only converts parts of the domain name that // have non-ASCII characters, i.e. it doesn't matter if // you call it with a domain that already is ASCII-only. this.hostname = punycode.toASCII(this.hostname); } var p = this.port ? ':' + this.port : ''; var h = this.hostname || ''; this.host = h + p; // strip [ and ] from the hostname // the host field still retains them, though if (ipv6Hostname) { this.hostname = this.hostname.slice(1, -1); if (rest[0] !== '/') { rest = '/' + rest; } } } // now rest is set to the post-host stuff. // chop off any delim chars. if (!unsafeProtocol[lowerProto]) { // First, make 100% sure that any "autoEscape" chars get // escaped, even if encodeURIComponent doesn't think they // need to be. var _result = autoEscapeStr(rest); if (_result !== undefined) rest = _result; } var questionIdx = -1; var hashIdx = -1; for (i = 0; i < rest.length; ++i) { var _code = rest.charCodeAt(i); if (_code === 35 /*#*/) { this.hash = rest.slice(i); hashIdx = i; break; } else if (_code === 63 /*?*/ && questionIdx === -1) { questionIdx = i; } } if (questionIdx !== -1) { if (hashIdx === -1) { this.search = rest.slice(questionIdx); this.query = rest.slice(questionIdx + 1); } else { this.search = rest.slice(questionIdx, hashIdx); this.query = rest.slice(questionIdx + 1, hashIdx); } if (parseQueryString) { this.query = querystring.parse(this.query); } } else if (parseQueryString) { // no query string, but parseQueryString still requested this.search = ''; this.query = {}; } var firstIdx = questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx) ? questionIdx : hashIdx; if (firstIdx === -1) { if (rest.length > 0) this.pathname = rest; } else if (firstIdx > 0) { this.pathname = rest.slice(0, firstIdx); } if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) { this.pathname = '/'; } // to support http.request if (this.pathname || this.search) { var _p = this.pathname || ''; var s = this.search || ''; this.path = _p + s; } // finally, reconstruct the href based on what has been validated. this.href = this.format(); return this; }; /* istanbul ignore next: improve coverage */ function validateHostname(self, rest, hostname) { for (var i = 0, lastPos; i <= hostname.length; ++i) { var code; if (i < hostname.length) code = hostname.charCodeAt(i); if (code === 46 /*.*/ || i === hostname.length) { if (i - lastPos > 0) { if (i - lastPos > 63) { self.hostname = hostname.slice(0, lastPos + 63); return '/' + hostname.slice(lastPos + 63) + rest; } } lastPos = i + 1; continue; } else if (code >= 48 /*0*/ && code <= 57 /*9*/ || code >= 97 /*a*/ && code <= 122 /*z*/ || code === 45 /*-*/ || code >= 65 /*A*/ && code <= 90 /*Z*/ || code === 43 /*+*/ || code === 95 /*_*/ || /* BEGIN MONGO URI PATCH */ code === 44 /*,*/ || code === 58 /*:*/ || /* END MONGO URI PATCH */ code > 127) { continue; } // Invalid host character self.hostname = hostname.slice(0, i); if (i < hostname.length) return '/' + hostname.slice(i) + rest; break; } } /* istanbul ignore next: improve coverage */ function autoEscapeStr(rest) { var newRest = ''; var lastPos = 0; for (var i = 0; i < rest.length; ++i) { // Automatically escape all delimiters and unwise characters from RFC 2396 // Also escape single quotes in case of an XSS attack switch (rest.charCodeAt(i)) { case 9: // '\t' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%09'; lastPos = i + 1; break; case 10: // '\n' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%0A'; lastPos = i + 1; break; case 13: // '\r' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%0D'; lastPos = i + 1; break; case 32: // ' ' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%20'; lastPos = i + 1; break; case 34: // '"' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%22'; lastPos = i + 1; break; case 39: // '\'' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%27'; lastPos = i + 1; break; case 60: // '<' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%3C'; lastPos = i + 1; break; case 62: // '>' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%3E'; lastPos = i + 1; break; case 92: // '\\' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%5C'; lastPos = i + 1; break; case 94: // '^' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%5E'; lastPos = i + 1; break; case 96: // '`' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%60'; lastPos = i + 1; break; case 123: // '{' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%7B'; lastPos = i + 1; break; case 124: // '|' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%7C'; lastPos = i + 1; break; case 125: // '}' if (i - lastPos > 0) newRest += rest.slice(lastPos, i); newRest += '%7D'; lastPos = i + 1; break; } } if (lastPos === 0) return; if (lastPos < rest.length) return newRest + rest.slice(lastPos);else return newRest; } // format a parsed object into a url string /* istanbul ignore next: improve coverage */ function urlFormat(obj) { // ensure it's an object, and not a string url. // If it's an obj, this is a no-op. // this way, you can call url_format() on strings // to clean up potentially wonky urls. if (typeof obj === 'string') obj = urlParse(obj);else if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' || obj === null) throw new TypeError('Parameter "urlObj" must be an object, not ' + obj === null ? 'null' : typeof obj === 'undefined' ? 'undefined' : _typeof(obj));else if (!(obj instanceof Url)) return Url.prototype.format.call(obj); return obj.format(); } /* istanbul ignore next: improve coverage */ Url.prototype.format = function () { var auth = this.auth || ''; if (auth) { auth = encodeAuth(auth); auth += '@'; } var protocol = this.protocol || ''; var pathname = this.pathname || ''; var hash = this.hash || ''; var host = false; var query = ''; if (this.host) { host = auth + this.host; } else if (this.hostname) { host = auth + (this.hostname.indexOf(':') === -1 ? this.hostname : '[' + this.hostname + ']'); if (this.port) { host += ':' + this.port; } } if (this.query !== null && _typeof(this.query) === 'object') query = querystring.stringify(this.query); var search = this.search || query && '?' + query || ''; if (protocol && protocol.charCodeAt(protocol.length - 1) !== 58 /*:*/) protocol += ':'; var newPathname = ''; var lastPos = 0; for (var i = 0; i < pathname.length; ++i) { switch (pathname.charCodeAt(i)) { case 35: // '#' if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += '%23'; lastPos = i + 1; break; case 63: // '?' if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += '%3F'; lastPos = i + 1; break; } } if (lastPos > 0) { if (lastPos !== pathname.length) pathname = newPathname + pathname.slice(lastPos);else pathname = newPathname; } // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. if (this.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) { host = '//' + (host || ''); if (pathname && pathname.charCodeAt(0) !== 47 /*/*/) pathname = '/' + pathname; } else if (!host) { host = ''; } search = search.replace('#', '%23'); if (hash && hash.charCodeAt(0) !== 35 /*#*/) hash = '#' + hash; if (search && search.charCodeAt(0) !== 63 /*?*/) search = '?' + search; return protocol + host + pathname + search + hash; }; /* istanbul ignore next: improve coverage */ function urlResolve(source, relative) { return urlParse(source, false, true).resolve(relative); } /* istanbul ignore next: improve coverage */ Url.prototype.resolve = function (relative) { return this.resolveObject(urlParse(relative, false, true)).format(); }; /* istanbul ignore next: improve coverage */ function urlResolveObject(source, relative) { if (!source) return relative; return urlParse(source, false, true).resolveObject(relative); } /* istanbul ignore next: improve coverage */ Url.prototype.resolveObject = function (relative) { if (typeof relative === 'string') { var rel = new Url(); rel.parse(relative, false, true); relative = rel; } var result = new Url(); var tkeys = Object.keys(this); for (var tk = 0; tk < tkeys.length; tk++) { var tkey = tkeys[tk]; result[tkey] = this[tkey]; } // hash is always overridden, no matter what. // even href="" will remove it. result.hash = relative.hash; // if the relative url is empty, then there's nothing left to do here. if (relative.href === '') { result.href = result.format(); return result; } // hrefs like //foo/bar always cut to the protocol. if (relative.slashes && !relative.protocol) { // take everything except the protocol from relative var rkeys = Object.keys(relative); for (var rk = 0; rk < rkeys.length; rk++) { var rkey = rkeys[rk]; if (rkey !== 'protocol') result[rkey] = relative[rkey]; } //urlParse appends trailing / to urls like http://www.example.com if (slashedProtocol[result.protocol] && result.hostname && !result.pathname) { result.path = result.pathname = '/'; } result.href = result.format(); return result; } if (relative.protocol && relative.protocol !== result.protocol) { // if it's a known url protocol, then changing // the protocol does weird things // first, if it's not file:, then we MUST have a host, // and if there was a path // to begin with, then we MUST have a path. // if it is file:, then the host is dropped, // because that's known to be hostless. // anything else is assumed to be absolute. if (!slashedProtocol[relative.protocol]) { var keys = Object.keys(relative); for (var v = 0; v < keys.length; v++) { var k = keys[v]; result[k] = relative[k]; } result.href = result.format(); return result; } result.protocol = relative.protocol; if (!relative.host && !/^file:?$/.test(relative.protocol) && !hostlessProtocol[relative.protocol]) { var _relPath = (relative.pathname || '').split('/'); while (_relPath.length && !(relative.host = _relPath.shift())) {} if (!relative.host) relative.host = ''; if (!relative.hostname) relative.hostname = ''; if (_relPath[0] !== '') _relPath.unshift(''); if (_relPath.length < 2) _relPath.unshift(''); result.pathname = _relPath.join('/'); } else { result.pathname = relative.pathname; } result.search = relative.search; result.query = relative.query; result.host = relative.host || ''; result.auth = relative.auth; result.hostname = relative.hostname || relative.host; result.port = relative.port; // to support http.request if (result.pathname || result.search) { var p = result.pathname || ''; var s = result.search || ''; result.path = p + s; } result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; } var isSourceAbs = result.pathname && result.pathname.charAt(0) === '/'; var isRelAbs = relative.host || relative.pathname && relative.pathname.charAt(0) === '/'; var mustEndAbs = isRelAbs || isSourceAbs || result.host && relative.pathname; var removeAllDots = mustEndAbs; var srcPath = result.pathname && result.pathname.split('/') || []; var relPath = relative.pathname && relative.pathname.split('/') || []; var psychotic = result.protocol && !slashedProtocol[result.protocol]; // if the url is a non-slashed url, then relative // links like ../.. should be able // to crawl up to the hostname, as well. This is strange. // result.protocol has already been set by now. // Later on, put the first path part into the host field. if (psychotic) { result.hostname = ''; result.port = null; if (result.host) { if (srcPath[0] === '') srcPath[0] = result.host;else srcPath.unshift(result.host); } result.host = ''; if (relative.protocol) { relative.hostname = null; relative.port = null; if (relative.host) { if (relPath[0] === '') relPath[0] = relative.host;else relPath.unshift(relative.host); } relative.host = null; } mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); } if (isRelAbs) { // it's absolute. result.host = relative.host || relative.host === '' ? relative.host : result.host; result.hostname = relative.hostname || relative.hostname === '' ? relative.hostname : result.hostname; result.search = relative.search; result.query = relative.query; srcPath = relPath; // fall through to the dot-handling below. } else if (relPath.length) { // it's relative // throw away the existing file, and take the new path instead. if (!srcPath) srcPath = []; srcPath.pop(); srcPath = srcPath.concat(relPath); result.search = relative.search; result.query = relative.query; } else if (relative.search !== null && relative.search !== undefined) { // just pull out the search. // like href='?foo'. // Put this after the other two cases because it simplifies the booleans if (psychotic) { result.hostname = result.host = srcPath.shift(); //occasionally the auth can get stuck only in host //this especially happens in cases like //url.resolveObject('mailto:local1@domain1', 'local2@domain2') var authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; if (authInHost) { result.auth = authInHost.shift(); result.host = result.hostname = authInHost.shift(); } } result.search = relative.search; result.query = relative.query; //to support http.request if (result.pathname !== null || result.search !== null) { result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); } result.href = result.format(); return result; } if (!srcPath.length) { // no path at all. easy. // we've already handled the other stuff above. result.pathname = null; //to support http.request if (result.search) { result.path = '/' + result.search; } else { result.path = null; } result.href = result.format(); return result; } // if a url ENDs in . or .., then it must get a trailing slash. // however, if it ends in anything else non-slashy, // then it must NOT get a trailing slash. var last = srcPath.slice(-1)[0]; var hasTrailingSlash = (result.host || relative.host || srcPath.length > 1) && (last === '.' || last === '..') || last === ''; // strip single dots, resolve double dots to parent dir // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = srcPath.length; i >= 0; i--) { last = srcPath[i]; if (last === '.') { spliceOne(srcPath, i); } else if (last === '..') { spliceOne(srcPath, i); up++; } else if (up) { spliceOne(srcPath, i); up--; } } // if the path is allowed to go above the root, restore leading ..s if (!mustEndAbs && !removeAllDots) { for (; up--; up) { srcPath.unshift('..'); } } if (mustEndAbs && srcPath[0] !== '' && (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { srcPath.unshift(''); } if (hasTrailingSlash && srcPath.join('/').substr(-1) !== '/') { srcPath.push(''); } var isAbsolute = srcPath[0] === '' || srcPath[0] && srcPath[0].charAt(0) === '/'; // put the host back if (psychotic) { result.hostname = result.host = isAbsolute ? '' : srcPath.length ? srcPath.shift() : ''; //occasionally the auth can get stuck only in host //this especially happens in cases like //url.resolveObject('mailto:local1@domain1', 'local2@domain2') var _authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; if (_authInHost) { result.auth = _authInHost.shift(); result.host = result.hostname = _authInHost.shift(); } } mustEndAbs = mustEndAbs || result.host && srcPath.length; if (mustEndAbs && !isAbsolute) { srcPath.unshift(''); } if (!srcPath.length) { result.pathname = null; result.path = null; } else { result.pathname = srcPath.join('/'); } //to support request.http if (result.pathname !== null || result.search !== null) { result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); } result.auth = relative.auth || result.auth; result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; }; /* istanbul ignore next: improve coverage */ Url.prototype.parseHost = function () { var host = this.host; var port = portPattern.exec(host); if (port) { port = port[0]; if (port !== ':') { this.port = port.slice(1); } host = host.slice(0, host.length - port.length); } if (host) this.hostname = host; }; // About 1.5x faster than the two-arg version of Array#splice(). /* istanbul ignore next: improve coverage */ function spliceOne(list, index) { for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) { list[i] = list[k]; }list.pop(); } var hexTable = new Array(256); for (var i = 0; i < 256; ++i) { hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); } /* istanbul ignore next: improve coverage */ function encodeAuth(str) { // faster encodeURIComponent alternative for encoding auth uri components var out = ''; var lastPos = 0; for (var i = 0; i < str.length; ++i) { var c = str.charCodeAt(i); // These characters do not need escaping: // ! - . _ ~ // ' ( ) * : // digits // alpha (uppercase) // alpha (lowercase) if (c === 0x21 || c === 0x2D || c === 0x2E || c === 0x5F || c === 0x7E || c >= 0x27 && c <= 0x2A || c >= 0x30 && c <= 0x3A || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A) { continue; } if (i - lastPos > 0) out += str.slice(lastPos, i); lastPos = i + 1; // Other ASCII characters if (c < 0x80) { out += hexTable[c]; continue; } // Multi-byte characters ... if (c < 0x800) { out += hexTable[0xC0 | c >> 6] + hexTable[0x80 | c & 0x3F]; continue; } if (c < 0xD800 || c >= 0xE000) { out += hexTable[0xE0 | c >> 12] + hexTable[0x80 | c >> 6 & 0x3F] + hexTable[0x80 | c & 0x3F]; continue; } // Surrogate pair ++i; var c2; if (i < str.length) c2 = str.charCodeAt(i) & 0x3FF;else c2 = 0; c = 0x10000 + ((c & 0x3FF) << 10 | c2); out += hexTable[0xF0 | c >> 18] + hexTable[0x80 | c >> 12 & 0x3F] + hexTable[0x80 | c >> 6 & 0x3F] + hexTable[0x80 | c & 0x3F]; } if (lastPos === 0) return str; if (lastPos < str.length) return out + str.slice(lastPos); return out; } |